mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
new TransformManager class
This commit is contained in:
parent
ed335a9af0
commit
ace956c215
2 changed files with 611 additions and 0 deletions
449
Ghidra/Features/Decompiler/src/decompile/cpp/transform.cc
Normal file
449
Ghidra/Features/Decompiler/src/decompile/cpp/transform.cc
Normal file
|
@ -0,0 +1,449 @@
|
|||
/* ###
|
||||
* 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 "transform.hh"
|
||||
#include "funcdata.hh"
|
||||
|
||||
/// Create the Varnode object (constant, unique, vector piece) described by the
|
||||
/// given placeholder. If the Varnode is an output, assume the op already exists
|
||||
/// and create the Varnode as an output. Set the \b replacement field with the
|
||||
/// new Varnode.
|
||||
/// \param fd is the function in which to create the replacement
|
||||
void TransformVar::createReplacement(Funcdata *fd)
|
||||
|
||||
{
|
||||
switch(type) {
|
||||
case TransformVar::preexisting:
|
||||
replacement = vn;
|
||||
break;
|
||||
case TransformVar::constant:
|
||||
replacement = fd->newConstant(size,val);
|
||||
break;
|
||||
case TransformVar::normal_temp:
|
||||
if (def == (TransformOp *)0)
|
||||
replacement = fd->newUnique(size);
|
||||
else
|
||||
replacement = fd->newUniqueOut(size,def->replacement);
|
||||
break;
|
||||
case TransformVar::piece:
|
||||
{
|
||||
Address addr = vn->getAddr() + (int4)val;
|
||||
if (def == (TransformOp *)0)
|
||||
replacement = fd->newVarnode(size,addr);
|
||||
else
|
||||
replacement = fd->newVarnodeOut(size, addr, def->replacement);
|
||||
break;
|
||||
}
|
||||
case TransformVar::constant_iop:
|
||||
{
|
||||
PcodeOp *indeffect = PcodeOp::getOpFromConst(Address(fd->getArch()->getIopSpace(),val));
|
||||
replacement = fd->newVarnodeIop(indeffect);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw LowlevelError("Bad TransformVar type");
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new PcodeOp or modify an existing one so that it matches this placeholder description.
|
||||
/// Go ahead an insert the new PcodeOp into the basic block if possible
|
||||
/// \param fd is the function in which to make the modifications
|
||||
void TransformOp::createReplacement(Funcdata *fd)
|
||||
|
||||
{
|
||||
if ((special & TransformOp::op_preexisting)!=0) {
|
||||
replacement = op;
|
||||
fd->opSetOpcode(op, opc);
|
||||
while(input.size() < op->numInput())
|
||||
fd->opRemoveInput(op, op->numInput()-1);
|
||||
while(op->numInput() < input.size())
|
||||
fd->opInsertInput(op, (Varnode *)0, op->numInput()-1);
|
||||
}
|
||||
else {
|
||||
replacement = fd->newOp(input.size(),op->getAddr());
|
||||
fd->opSetOpcode(replacement, opc);
|
||||
if (output != (TransformVar *)0)
|
||||
output->createReplacement(fd);
|
||||
if (follow == (TransformOp *)0) // Can be inserted immediately
|
||||
fd->opInsertBefore(replacement, op);
|
||||
}
|
||||
}
|
||||
|
||||
/// \param fd is the function into which the PcodeOp will be inserted
|
||||
/// \return \b true if the op is successfully inserted or already inserted
|
||||
bool TransformOp::attemptInsertion(Funcdata *fd)
|
||||
|
||||
{
|
||||
if (follow != (TransformOp *)0) {
|
||||
if (follow->follow == (TransformOp *)0) { // Check if the follow is inserted
|
||||
fd->opInsertBefore(replacement,follow->replacement);
|
||||
follow = (TransformOp *)0; // Mark that this has been inserted
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true; // Already inserted
|
||||
}
|
||||
|
||||
/// \param vn is the preexisting Varnode to create a placeholder for
|
||||
/// \return the new placeholder node
|
||||
TransformVar *TransformManager::newPreexistingVarnode(Varnode *vn)
|
||||
|
||||
{
|
||||
newVarnodes.push_back(TransformVar());
|
||||
TransformVar *res = &newVarnodes.back();
|
||||
res->vn = vn;
|
||||
res->replacement = (Varnode *)0;
|
||||
res->size = vn->getSize();
|
||||
res->def = (TransformOp *)0;
|
||||
res->type = TransformVar::preexisting;
|
||||
MapKey key(vn->getCreateIndex(),0);
|
||||
pieceMap[key] = res; // Enter preexisting Varnode into map, so we don't make another placeholder
|
||||
return res;
|
||||
}
|
||||
|
||||
/// \param size is the size in bytes of the new unique Varnode
|
||||
/// \return the new placeholder node
|
||||
TransformVar *TransformManager::newUnique(int4 size)
|
||||
|
||||
{
|
||||
newVarnodes.push_back(TransformVar());
|
||||
TransformVar *res = &newVarnodes.back();
|
||||
res->replacement = (Varnode *)0;
|
||||
res->size = size;
|
||||
res->def = (TransformOp *)0;
|
||||
res->type = TransformVar::normal_temp;
|
||||
return res;
|
||||
}
|
||||
|
||||
/// \param size is the size in bytes of the new constant
|
||||
/// \param val is the value of the new constant
|
||||
/// \return the new placeholder node
|
||||
TransformVar *TransformManager::newConstant(int4 size,uintb val)
|
||||
|
||||
{
|
||||
newVarnodes.push_back(TransformVar());
|
||||
TransformVar *res = &newVarnodes.back();
|
||||
res->replacement = (Varnode *)0;
|
||||
res->size = size;
|
||||
res->val = val;
|
||||
res->def = (TransformOp *)0;
|
||||
res->type = TransformVar::constant;
|
||||
return res;
|
||||
}
|
||||
|
||||
TransformVar *TransformManager::newIop(Varnode *vn)
|
||||
|
||||
{
|
||||
newVarnodes.push_back(TransformVar());
|
||||
TransformVar *res = &newVarnodes.back();
|
||||
res->vn = (Varnode *)0;
|
||||
res->replacement = (Varnode *)0;
|
||||
res->size = vn->getSize();
|
||||
res->val = vn->getOffset(); // The encoded iop
|
||||
res->def = (TransformOp *)0;
|
||||
res->type = TransformVar::constant_iop;
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Given a single logical value within a larger Varnode, create a placeholder for
|
||||
/// that logical value.
|
||||
/// \param vn is the large Varnode
|
||||
/// \param size is the size of the logical value in bytes
|
||||
/// \param lsbOffset is the number of least significant bytes of the Varnode dropped from the value
|
||||
/// \return the placeholder variable
|
||||
TransformVar *TransformManager::newPiece(Varnode *vn,int4 size,int4 lsbOffset)
|
||||
|
||||
{
|
||||
newVarnodes.push_back(TransformVar());
|
||||
TransformVar *res = &newVarnodes.back();
|
||||
res->vn = vn;
|
||||
res->replacement = (Varnode *)0;
|
||||
res->size = size;
|
||||
res->def = (TransformOp *)0;
|
||||
res->type = TransformVar::piece;
|
||||
MapKey key(vn->getCreateIndex(),lsbOffset);
|
||||
pieceMap[key] = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
/// \brief Create placeholder nodes splitting a Varnode into its lanes
|
||||
///
|
||||
/// Given a big Varnode and a lane description, create placeholders for all the explicit pieces
|
||||
/// that the big Varnode will be split into.
|
||||
/// \param res will hold references to the new placeholders in significance order
|
||||
/// \param vn is the big Varnode to split
|
||||
/// \param description shows how the big Varnode will be split
|
||||
void TransformManager::newSplit(vector<TransformVar *> &res,Varnode *vn,const LaneDescription &description)
|
||||
|
||||
{
|
||||
int4 num = description.getNumLanes();
|
||||
res.resize(num,(TransformVar *)0);
|
||||
for(int4 i=0;i<num;++i) {
|
||||
newVarnodes.push_back(TransformVar());
|
||||
TransformVar *newVar = &newVarnodes.back();
|
||||
newVar->vn = vn;
|
||||
newVar->replacement = (Varnode *)0;
|
||||
newVar->size = description.getSize(i);
|
||||
newVar->def = (TransformOp *)0;
|
||||
newVar->type = TransformVar::piece;
|
||||
MapKey key(vn->getCreateIndex(),description.getPosition(i));
|
||||
pieceMap[key] = newVar;
|
||||
res[i] = newVar;
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Create a new placeholder op intended to replace an existing op
|
||||
///
|
||||
/// An uninitialized placeholder for the new op is created.
|
||||
/// \param numParams is the number of Varnode inputs intended for the new op
|
||||
/// \param opc is the opcode of the new op
|
||||
/// \param replace is the existing op the new op will replace
|
||||
/// \return the new placeholder node
|
||||
TransformOp *TransformManager::newOpReplace(int4 numParams,OpCode opc,PcodeOp *replace)
|
||||
|
||||
{
|
||||
newOps.push_back(TransformOp());
|
||||
TransformOp &rop(newOps.back());
|
||||
rop.op = replace;
|
||||
rop.replacement = (PcodeOp *)0;
|
||||
rop.opc = opc;
|
||||
rop.special = TransformOp::op_replacement;
|
||||
rop.output = (TransformVar *)0;
|
||||
rop.follow = (TransformOp *)0;
|
||||
rop.input.resize(numParams,(TransformVar *)0);
|
||||
return &rop;
|
||||
}
|
||||
|
||||
/// \brief Create a new placeholder op that will not replace an existing op
|
||||
///
|
||||
/// An uninitialized placeholder for the new op is created. When (if) the new op is created
|
||||
/// it will not replace an existing op. The op that follows it must be given.
|
||||
/// \param numParams is the number of Varnode inputs intended for the new op
|
||||
/// \param opc is the opcode of the new op
|
||||
/// \param follow is the placeholder for the op that follow the new op when it is created
|
||||
/// \return the new placeholder node
|
||||
TransformOp *TransformManager::newOp(int4 numParams,OpCode opc,TransformOp *follow)
|
||||
|
||||
{
|
||||
newOps.push_back(TransformOp());
|
||||
TransformOp &rop(newOps.back());
|
||||
rop.op = follow->op;
|
||||
rop.replacement = (PcodeOp *)0;
|
||||
rop.opc = opc;
|
||||
rop.special = 0;
|
||||
rop.output = (TransformVar *)0;
|
||||
rop.follow = follow;
|
||||
rop.input.resize(numParams,(TransformVar *)0);
|
||||
return &rop;
|
||||
}
|
||||
|
||||
/// \brief Create a new placeholder op for an existing PcodeOp
|
||||
///
|
||||
/// An uninitialized placeholder for the existing op is created. When applied, this causes
|
||||
/// the op to be transformed as described by the placeholder, changing its opcode and
|
||||
/// inputs. The output however is unaffected.
|
||||
/// \param numParams is the number of Varnode inputs intended for the transformed op
|
||||
/// \param opc is the opcode of the transformed op
|
||||
/// \param originalOp is the preexisting PcodeOp
|
||||
/// \return the new placeholder node
|
||||
TransformOp *TransformManager::newPreexistingOp(int4 numParams,OpCode opc,PcodeOp *originalOp)
|
||||
|
||||
{
|
||||
newOps.push_back(TransformOp());
|
||||
TransformOp &rop(newOps.back());
|
||||
rop.op = originalOp;
|
||||
rop.replacement = (PcodeOp *)0;
|
||||
rop.opc = opc;
|
||||
rop.special = TransformOp::op_preexisting;
|
||||
rop.output = (TransformVar *)0;
|
||||
rop.follow = (TransformOp *)0;
|
||||
rop.input.resize(numParams,(TransformVar *)0);
|
||||
return &rop;
|
||||
}
|
||||
|
||||
/// Check if a placeholder node was created for the preexisting Varnode for,
|
||||
/// otherwise create a new one.
|
||||
/// \param vn is the preexisting Varnode to find a placeholder for
|
||||
/// \return the placeholder node
|
||||
TransformVar *TransformManager::getPreexistingVarnode(Varnode *vn)
|
||||
|
||||
{
|
||||
map<MapKey,TransformVar *>::const_iterator iter;
|
||||
MapKey key(vn->getCreateIndex(),0);
|
||||
iter = pieceMap.find(key);
|
||||
if (iter != pieceMap.end())
|
||||
return (*iter).second;
|
||||
return newPreexistingVarnode(vn);
|
||||
}
|
||||
|
||||
/// Given a big Varnode, find the placeholder corresponding to the logical value
|
||||
/// given by a size and significance offset. If it doesn't exist, create it.
|
||||
/// \param vn is the big Varnode containing the logical value
|
||||
/// \param size is the size of the logical value in bytes
|
||||
/// \param lsbOffset is the signficance offset of the logical value within the Varnode
|
||||
/// \return the found/created placeholder
|
||||
TransformVar *TransformManager::getPiece(Varnode *vn,int4 size,int4 lsbOffset)
|
||||
|
||||
{
|
||||
map<MapKey,TransformVar *>::const_iterator iter;
|
||||
MapKey key(vn->getCreateIndex(),lsbOffset);
|
||||
iter = pieceMap.find(key);
|
||||
if (iter != pieceMap.end()) {
|
||||
return (*iter).second;
|
||||
}
|
||||
return newPiece(vn,size,lsbOffset);
|
||||
}
|
||||
|
||||
/// \brief Find (or create) placeholder nodes splitting a Varnode into its lanes
|
||||
///
|
||||
/// Given a big Varnode and a lane description, look up placeholders for all its
|
||||
/// explicit pieces. If they don't exist, create them.
|
||||
/// \param res will hold the array of recovered placeholders in significance order
|
||||
/// \param vn is the big Varnode to split
|
||||
/// \param description shows how the big Varnode will be split
|
||||
void TransformManager::getSplit(vector<TransformVar *> &res,Varnode *vn,const LaneDescription &description)
|
||||
|
||||
{
|
||||
map<MapKey,TransformVar *>::const_iterator iter;
|
||||
MapKey key(vn->getCreateIndex(),0);
|
||||
iter = pieceMap.lower_bound(key);
|
||||
if (iter != pieceMap.end() && (*iter).first.getCreateIndex() == vn->getCreateIndex()) {
|
||||
int4 num = description.getNumLanes();
|
||||
res.resize(num,(TransformVar *)0);
|
||||
for(int4 i=0;i<num;++i) {
|
||||
res[i] = (*iter).second;
|
||||
++iter;
|
||||
}
|
||||
return;
|
||||
}
|
||||
newSplit(res,vn,description);
|
||||
}
|
||||
|
||||
void TransformManager::opSetInput(TransformOp *rop,TransformVar *rvn,int4 slot)
|
||||
|
||||
{
|
||||
rop->input[slot] = rvn;
|
||||
}
|
||||
|
||||
/// \brief Handle some special PcodeOp marking
|
||||
/// If a PcodeOp is an INDIRECT creation, we need to do special marking of the op and Varnodes
|
||||
/// \param rop is the placeholder op with the special requirement
|
||||
void TransformManager::specialHandling(TransformOp &rop)
|
||||
{
|
||||
if ((rop.special & TransformOp::indirect_creation) != 0)
|
||||
fd->markIndirectCreation(rop.replacement, false);
|
||||
else if ((rop.special & TransformOp::indirect_creation_possible_out) != 0)
|
||||
fd->markIndirectCreation(rop.replacement, true);
|
||||
}
|
||||
|
||||
/// Run through the list of TransformOp placeholders and create the actual PcodeOp object.
|
||||
/// If the op has an output Varnode, create it. Make sure all the new ops are inserted in
|
||||
/// control flow.
|
||||
void TransformManager::createOps(void)
|
||||
|
||||
{
|
||||
list<TransformOp>::iterator iter;
|
||||
for(iter=newOps.begin();iter!=newOps.end();++iter)
|
||||
(*iter).createReplacement(fd);
|
||||
|
||||
int4 followCount;
|
||||
do {
|
||||
followCount = 0;
|
||||
for(iter=newOps.begin();iter!=newOps.end();++iter) {
|
||||
if (!(*iter).attemptInsertion(fd))
|
||||
followCount += 1;
|
||||
}
|
||||
} while(followCount != 0);
|
||||
}
|
||||
|
||||
void TransformManager::createVarnodes(void)
|
||||
|
||||
{
|
||||
list<TransformVar>::iterator iter;
|
||||
for(iter=newVarnodes.begin();iter!=newVarnodes.end();++iter) {
|
||||
(*iter).createReplacement(fd);
|
||||
}
|
||||
}
|
||||
|
||||
void TransformManager::removeOld(void)
|
||||
|
||||
{
|
||||
list<TransformOp>::iterator iter;
|
||||
for(iter=newOps.begin();iter!=newOps.end();++iter) {
|
||||
TransformOp &rop(*iter);
|
||||
if ((rop.special & TransformOp::op_replacement) != 0) {
|
||||
if (!rop.op->isDead())
|
||||
fd->opDestroy(rop.op); // Destroy old op (and its output Varnode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect all the Varnodes that are inputs and are getting replaced.
|
||||
/// There may be multiple references so we dedup with marks.
|
||||
/// Remove all the replaced input Varnodes.
|
||||
/// Mark all the replacement Varnodes as inputs.
|
||||
void TransformManager::transformInputVarnodes(void)
|
||||
|
||||
{
|
||||
list<TransformVar>::iterator iter;
|
||||
vector<Varnode *> deadList;
|
||||
|
||||
for(iter=newVarnodes.begin();iter!=newVarnodes.end();++iter) {
|
||||
TransformVar &rvn(*iter);
|
||||
if (rvn.type == TransformVar::piece && rvn.def == (TransformOp *)0) {
|
||||
if (!rvn.vn->isMark()) {
|
||||
rvn.vn->setMark();
|
||||
deadList.push_back(rvn.vn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int4 i=0;i<deadList.size();++i)
|
||||
fd->deleteVarnode(deadList[i]);
|
||||
|
||||
for(iter=newVarnodes.begin();iter!=newVarnodes.end();++iter) {
|
||||
TransformVar &rvn(*iter);
|
||||
if (rvn.type == TransformVar::piece && rvn.def == (TransformOp *)0) {
|
||||
rvn.replacement = fd->setInputVarnode(rvn.replacement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TransformManager::placeInputs(void)
|
||||
|
||||
{
|
||||
list<TransformOp>::iterator iter;
|
||||
for(iter=newOps.begin();iter!=newOps.end();++iter) {
|
||||
TransformOp &rop(*iter);
|
||||
PcodeOp *op = rop.replacement;
|
||||
for(int4 i=0;i<rop.input.size();++i) {
|
||||
TransformVar *rvn = rop.input[i];
|
||||
Varnode *vn = rvn->replacement;
|
||||
fd->opSetInput(op, vn, i);
|
||||
}
|
||||
specialHandling(rop);
|
||||
}
|
||||
}
|
||||
|
||||
void TransformManager::apply(void)
|
||||
|
||||
{
|
||||
createOps();
|
||||
createVarnodes();
|
||||
removeOld();
|
||||
transformInputVarnodes();
|
||||
placeInputs();
|
||||
}
|
162
Ghidra/Features/Decompiler/src/decompile/cpp/transform.hh
Normal file
162
Ghidra/Features/Decompiler/src/decompile/cpp/transform.hh
Normal file
|
@ -0,0 +1,162 @@
|
|||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
#ifndef __TRANSFORM__
|
||||
#define __TRANSFORM__
|
||||
|
||||
#include "varnode.hh"
|
||||
class Funcdata; // Forward declaration
|
||||
class TransformOp;
|
||||
|
||||
/// \brief Placeholder node for Varnode that will exist after a transform is applied to a function
|
||||
class TransformVar {
|
||||
friend class TransformManager;
|
||||
public:
|
||||
/// Types of replacement Varnodes
|
||||
enum {
|
||||
piece = 1, ///< New Varnode is a piece of an original Varnode
|
||||
preexisting = 2, ///< Varnode preexisted in the original data-flow
|
||||
normal_temp = 3, ///< A new temporary (unique space) Varnode
|
||||
constant = 4, ///< A new constant Varnode
|
||||
constant_iop = 5, ///< Special iop constant encoding a PcodeOp reference
|
||||
};
|
||||
private:
|
||||
Varnode *vn; ///< Original \b big Varnode of which \b this is a component
|
||||
Varnode *replacement; ///< The new explicit lane Varnode
|
||||
int4 size; ///< Size of the lane Varnode in bytes
|
||||
uintb val; ///< Value of constant or position within the original big Varnode
|
||||
TransformOp *def; ///< Defining op for new Varnode
|
||||
uint4 type; ///< Type of new Varnode
|
||||
void createReplacement(Funcdata *fd); ///< Create the new/modified variable this placeholder represents
|
||||
};
|
||||
|
||||
/// \brief Placeholder node for PcodeOp that will exist after a transform is applied to a function
|
||||
class TransformOp {
|
||||
friend class TransformManager;
|
||||
public:
|
||||
/// Special annotations on new pcode ops
|
||||
enum {
|
||||
op_replacement = 1, ///< Op replaces an existing op
|
||||
op_preexisting = 2, ///< Op already exists (but will be transformed)
|
||||
indirect_creation = 4, ///< Mark op as indirect creation
|
||||
indirect_creation_possible_out = 8 ///< Mark op as indirect creation and possible call output
|
||||
};
|
||||
private:
|
||||
PcodeOp *op; ///< Original op which \b this is splitting (or null)
|
||||
PcodeOp *replacement; ///< The new replacement op
|
||||
OpCode opc; ///< Opcode of the new op
|
||||
uint4 special; ///< Special handling code when creating
|
||||
TransformVar *output; ///< Varnode output
|
||||
vector<TransformVar *> input; ///< Varnode inputs
|
||||
TransformOp *follow; ///< The following op after \b this (if not null)
|
||||
void createReplacement(Funcdata *fd); ///< Create the new/modified op this placeholder represents
|
||||
bool attemptInsertion(Funcdata *fd); ///< Try to put the new PcodeOp into its basic block
|
||||
};
|
||||
|
||||
/// \brief Description of logical lanes within a \b big Varnode
|
||||
///
|
||||
/// A \b lane is a byte offset and size within a Varnode. Lanes within a
|
||||
/// Varnode are disjoint. In general, we expect a Varnode to be tiled with
|
||||
/// lanes all of the same size, but the API allows for possibly non-uniform lanes.
|
||||
class LaneDescription {
|
||||
int4 size; ///< Size of (all) lanes
|
||||
int4 numLanes; ///< Number of distinct lanes
|
||||
public:
|
||||
LaneDescription(int4 origSize,int4 sz) { size = sz; numLanes = origSize / sz; } ///< Constructor
|
||||
int4 getNumLanes(void) const { return numLanes; } ///< Get the total number of lanes
|
||||
int4 getSize(int4 i) const { return size; } ///< Get the size of the i-th lane
|
||||
int4 getPosition(int4 i) const { return size * i; } ///< Get the significance offset of the i-th lane
|
||||
};
|
||||
|
||||
/// \brief Class for splitting larger registers holding smaller logical lanes
|
||||
///
|
||||
/// Given a starting Varnode in the data-flow, look for evidence of the Varnode
|
||||
/// being interpreted as disjoint logical values concatenated together (lanes).
|
||||
/// If the interpretation is consistent for data-flow involving the Varnode, split
|
||||
/// Varnode and data-flow into explicit operations on the lanes.
|
||||
class TransformManager {
|
||||
/// \brief Key for mapping from a \b big Varnode to its pieces
|
||||
class MapKey {
|
||||
uint4 create_index; ///< Creation index of Varnode being split
|
||||
int4 position; ///< Position within the Varnode
|
||||
public:
|
||||
MapKey(uint4 index,int4 pos) { create_index = index; position = pos; } ///< Constructor
|
||||
uint4 getCreateIndex(void) const { return create_index; } ///< Return the creation index part of \b this key
|
||||
bool operator<(const MapKey &op2) const; ///< Comparator function for \b this key
|
||||
};
|
||||
|
||||
Funcdata *fd; ///< Function being operated on
|
||||
map<MapKey,TransformVar *> pieceMap; ///< Map from large Varnodes to their new pieces
|
||||
list<TransformVar> newVarnodes; ///< Storage for Varnode placeholder nodes
|
||||
list<TransformOp> newOps; ///< Storage for PcodeOp placeholder nodes
|
||||
|
||||
void specialHandling(TransformOp &rop);
|
||||
void createOps(void); ///< Create a new op for each placeholder
|
||||
void createVarnodes(void); ///< Create a Varnode for each placeholder
|
||||
void removeOld(void); ///< Remove old preexisting PcodeOps and Varnodes that are now obsolete
|
||||
void transformInputVarnodes(void); ///< Remove old input Varnodes, mark new input Varnodes
|
||||
void placeInputs(void); ///< Set input Varnodes for all new ops
|
||||
public:
|
||||
TransformManager(Funcdata *f) { fd = f; } ///< Constructor
|
||||
TransformVar *newPreexistingVarnode(Varnode *vn); ///< Make placeholder for preexisting Varnode
|
||||
TransformVar *newUnique(int4 size); ///< Make placeholder for new unique space Varnode
|
||||
TransformVar *newConstant(int4 size,uintb val); ///< Make placeholder for constant Varnode
|
||||
TransformVar *newIop(Varnode *vn); ///< Make placeholder for special iop constant
|
||||
TransformVar *newPiece(Varnode *vn,int4 size,int4 lsbOffset); ///< Make placeholder for piece of a Varnode
|
||||
void newSplit(vector<TransformVar *> &res,Varnode *vn,const LaneDescription &description);
|
||||
TransformOp *newOpReplace(int4 numParams,OpCode opc,PcodeOp *replace);
|
||||
TransformOp *newOp(int4 numParams,OpCode opc,TransformOp *follow);
|
||||
TransformOp *newPreexistingOp(int4 numParams,OpCode opc,PcodeOp *originalOp);
|
||||
|
||||
TransformVar *getPreexistingVarnode(Varnode *vn); ///< Get (or create) placeholder for preexisting Varnode
|
||||
TransformVar *getPiece(Varnode *vn,int4 size,int4 lsbOffset); ///< Get (or create) placeholder piece
|
||||
void getSplit(vector<TransformVar *> &res,Varnode *vn,const LaneDescription &description);
|
||||
void opSetInput(TransformOp *rop,TransformVar *rvn,int4 slot); ///< Mark given variable as input to given op
|
||||
void opSetOutput(TransformOp *rop,TransformVar *rvn); ///< Mark given variable as output of given op
|
||||
|
||||
void apply(void); ///< Apply the full transform to the function
|
||||
};
|
||||
|
||||
/// \param op2 is the other key to compare with \b this
|
||||
/// \return \b true if \b this should come before the other key
|
||||
inline bool TransformManager::MapKey::operator<(const TransformManager::MapKey &op2) const
|
||||
|
||||
{
|
||||
if (create_index != op2.create_index)
|
||||
return (create_index < op2.create_index);
|
||||
return (position < op2.position);
|
||||
}
|
||||
|
||||
/// \param rop is the given placeholder op whose input is set
|
||||
/// \param rvn is the placeholder variable to set
|
||||
/// \param slot is the input position to set
|
||||
inline void TransformManager::opSetInput(TransformOp *rop,TransformVar *rvn,int4 slot)
|
||||
|
||||
{
|
||||
rop->input[slot] = rvn;
|
||||
}
|
||||
|
||||
/// Establish that the given op produces the given var as output.
|
||||
/// Mark both the \e output field of the TransformOp and the \e def field of the TransformVar.
|
||||
/// \param rop is the given op
|
||||
/// \param rvn is the given variable
|
||||
inline void TransformManager::opSetOutput(TransformOp *rop,TransformVar *rvn)
|
||||
|
||||
{
|
||||
rop->output = rvn;
|
||||
rvn->def = rop;
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue