ghidra/Ghidra/Features/Decompiler/src/decompile/cpp/semantics.cc
2024-02-28 18:39:15 +00:00

950 lines
25 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 "semantics.hh"
#include "translate.hh"
namespace ghidra {
ConstTpl::ConstTpl(const_type tp)
{ // Constructor for relative jump constants and uniques
type = tp;
}
ConstTpl::ConstTpl(const_type tp,uintb val)
{ // Constructor for real constants
type = tp;
value_real = val;
value.handle_index = 0;
select = v_space;
}
ConstTpl::ConstTpl(const_type tp,int4 ht,v_field vf)
{ // Constructor for handle constant
type = handle;
value.handle_index = ht;
select = vf;
value_real = 0;
}
ConstTpl::ConstTpl(const_type tp,int4 ht,v_field vf,uintb plus)
{
type = handle;
value.handle_index = ht;
select = vf;
value_real = plus;
}
ConstTpl::ConstTpl(AddrSpace *sid)
{
type = spaceid;
value.spaceid = sid;
}
bool ConstTpl::isConstSpace(void) const
{
if (type==spaceid)
return (value.spaceid->getType()==IPTR_CONSTANT);
return false;
}
bool ConstTpl::isUniqueSpace(void) const
{
if (type==spaceid)
return (value.spaceid->getType()==IPTR_INTERNAL);
return false;
}
bool ConstTpl::operator==(const ConstTpl &op2) const
{
if (type != op2.type) return false;
switch(type) {
case real:
return (value_real == op2.value_real);
case handle:
if (value.handle_index != op2.value.handle_index) return false;
if (select != op2.select) return false;
break;
case spaceid:
return (value.spaceid == op2.value.spaceid);
default: // Nothing additional to compare
break;
}
return true;
}
bool ConstTpl::operator<(const ConstTpl &op2) const
{
if (type != op2.type) return (type < op2.type);
switch(type) {
case real:
return (value_real < op2.value_real);
case handle:
if (value.handle_index != op2.value.handle_index)
return (value.handle_index < op2.value.handle_index);
if (select != op2.select) return (select < op2.select);
break;
case spaceid:
return (value.spaceid < op2.value.spaceid);
default: // Nothing additional to compare
break;
}
return false;
}
uintb ConstTpl::fix(const ParserWalker &walker) const
{ // Get the value of the ConstTpl in context
// NOTE: if the property is dynamic this returns the property
// of the temporary storage
switch(type) {
case j_start:
return walker.getAddr().getOffset(); // Fill in starting address placeholder with real address
case j_next:
return walker.getNaddr().getOffset(); // Fill in next address placeholder with real address
case j_next2:
return walker.getN2addr().getOffset(); // Fill in next2 address placeholder with real address
case j_flowref:
return walker.getRefAddr().getOffset();
case j_flowref_size:
return walker.getRefAddr().getAddrSize();
case j_flowdest:
return walker.getDestAddr().getOffset();
case j_flowdest_size:
return walker.getDestAddr().getAddrSize();
case j_curspace_size:
return walker.getCurSpace()->getAddrSize();
case j_curspace:
return (uintb)(uintp)walker.getCurSpace();
case handle:
{
const FixedHandle &hand(walker.getFixedHandle(value.handle_index));
switch(select) {
case v_space:
if (hand.offset_space == (AddrSpace *)0)
return (uintb)(uintp)hand.space;
return (uintb)(uintp)hand.temp_space;
case v_offset:
if (hand.offset_space==(AddrSpace *)0)
return hand.offset_offset;
return hand.temp_offset;
case v_size:
return hand.size;
case v_offset_plus:
if (hand.space != walker.getConstSpace()) { // If we are not a constant
if (hand.offset_space==(AddrSpace *)0)
return hand.offset_offset + (value_real&0xffff); // Adjust offset by truncation amount
return hand.temp_offset + (value_real&0xffff);
}
else { // If we are a constant, we want to return a shifted value
uintb val;
if (hand.offset_space==(AddrSpace *)0)
val = hand.offset_offset;
else
val = hand.temp_offset;
val >>= 8 * (value_real>>16);
return val;
}
}
break;
}
case j_relative:
case real:
return value_real;
case spaceid:
return (uintb)(uintp)value.spaceid;
}
return 0; // Should never reach here
}
AddrSpace *ConstTpl::fixSpace(const ParserWalker &walker) const
{ // Get the value of the ConstTpl in context
// when we know it is a space
switch(type) {
case j_curspace:
return walker.getCurSpace();
case handle:
{
const FixedHandle &hand(walker.getFixedHandle(value.handle_index));
switch(select) {
case v_space:
if (hand.offset_space == (AddrSpace *)0)
return hand.space;
return hand.temp_space;
default:
break;
}
break;
}
case spaceid:
return value.spaceid;
case j_flowref:
return walker.getRefAddr().getSpace();
default:
break;
}
throw LowlevelError("ConstTpl is not a spaceid as expected");
}
void ConstTpl::fillinSpace(FixedHandle &hand,const ParserWalker &walker) const
{ // Fill in the space portion of a FixedHandle, base on this ConstTpl
switch(type) {
case j_curspace:
hand.space = walker.getCurSpace();
return;
case handle:
{
const FixedHandle &otherhand(walker.getFixedHandle(value.handle_index));
switch(select) {
case v_space:
hand.space = otherhand.space;
return;
default:
break;
}
break;
}
case spaceid:
hand.space = value.spaceid;
return;
default:
break;
}
throw LowlevelError("ConstTpl is not a spaceid as expected");
}
void ConstTpl::fillinOffset(FixedHandle &hand,const ParserWalker &walker) const
{ // Fillin the offset portion of a FixedHandle, based on this ConstTpl
// If the offset value is dynamic, indicate this in the handle
// we don't just fill in the temporary variable offset
// we assume hand.space is already filled in
if (type == handle) {
const FixedHandle &otherhand(walker.getFixedHandle(value.handle_index));
hand.offset_space = otherhand.offset_space;
hand.offset_offset = otherhand.offset_offset;
hand.offset_size = otherhand.offset_size;
hand.temp_space = otherhand.temp_space;
hand.temp_offset = otherhand.temp_offset;
}
else {
hand.offset_space = (AddrSpace *)0;
hand.offset_offset = hand.space->wrapOffset(fix(walker));
}
}
void ConstTpl::transfer(const vector<HandleTpl *> &params)
{ // Replace old handles with new handles
if (type != handle) return;
HandleTpl *newhandle = params[value.handle_index];
switch(select) {
case v_space:
*this = newhandle->getSpace();
break;
case v_offset:
*this = newhandle->getPtrOffset();
break;
case v_offset_plus:
{
uintb tmp = value_real;
*this = newhandle->getPtrOffset();
if (type == real) {
value_real += (tmp&0xffff);
}
else if ((type == handle)&&(select == v_offset)) {
select = v_offset_plus;
value_real = tmp;
}
else
throw LowlevelError("Cannot truncate macro input in this way");
break;
}
case v_size:
*this = newhandle->getSize();
break;
}
}
void ConstTpl::changeHandleIndex(const vector<int4> &handmap)
{
if (type == handle)
value.handle_index = handmap[value.handle_index];
}
void ConstTpl::encode(Encoder &encoder) const
{
switch(type) {
case real:
encoder.openElement(sla::ELEM_CONST_REAL);
encoder.writeUnsignedInteger(sla::ATTRIB_VAL, value_real);
encoder.closeElement(sla::ELEM_CONST_REAL);
break;
case handle:
encoder.openElement(sla::ELEM_CONST_HANDLE);
encoder.writeSignedInteger(sla::ATTRIB_VAL, value.handle_index);
encoder.writeSignedInteger(sla::ATTRIB_S, select);
if (select == v_offset_plus)
encoder.writeUnsignedInteger(sla::ATTRIB_PLUS, value_real);
encoder.closeElement(sla::ELEM_CONST_HANDLE);
break;
case j_start:
encoder.openElement(sla::ELEM_CONST_START);
encoder.closeElement(sla::ELEM_CONST_START);
break;
case j_next:
encoder.openElement(sla::ELEM_CONST_NEXT);
encoder.closeElement(sla::ELEM_CONST_NEXT);
break;
case j_next2:
encoder.openElement(sla::ELEM_CONST_NEXT2);
encoder.closeElement(sla::ELEM_CONST_NEXT2);
break;
case j_curspace:
encoder.openElement(sla::ELEM_CONST_CURSPACE);
encoder.closeElement(sla::ELEM_CONST_CURSPACE);
break;
case j_curspace_size:
encoder.openElement(sla::ELEM_CONST_CURSPACE_SIZE);
encoder.closeElement(sla::ELEM_CONST_CURSPACE_SIZE);
break;
case spaceid:
encoder.openElement(sla::ELEM_CONST_SPACEID);
encoder.writeSpace(sla::ATTRIB_SPACE, value.spaceid);
encoder.closeElement(sla::ELEM_CONST_SPACEID);
break;
case j_relative:
encoder.openElement(sla::ELEM_CONST_RELATIVE);
encoder.writeUnsignedInteger(sla::ATTRIB_VAL, value_real);
encoder.closeElement(sla::ELEM_CONST_RELATIVE);
break;
case j_flowref:
encoder.openElement(sla::ELEM_CONST_FLOWREF);
encoder.closeElement(sla::ELEM_CONST_FLOWREF);
break;
case j_flowref_size:
encoder.openElement(sla::ELEM_CONST_FLOWREF_SIZE);
encoder.closeElement(sla::ELEM_CONST_FLOWREF_SIZE);
break;
case j_flowdest:
encoder.openElement(sla::ELEM_CONST_FLOWDEST);
encoder.closeElement(sla::ELEM_CONST_FLOWDEST);
break;
case j_flowdest_size:
encoder.openElement(sla::ELEM_CONST_FLOWDEST_SIZE);
encoder.closeElement(sla::ELEM_CONST_FLOWDEST_SIZE);
break;
}
}
void ConstTpl::decode(Decoder &decoder)
{
uint4 el = decoder.openElement();
if (el == sla::ELEM_CONST_REAL) {
type = real;
value_real = decoder.readUnsignedInteger(sla::ATTRIB_VAL);
}
else if (el == sla::ELEM_CONST_HANDLE) {
type = handle;
value.handle_index = decoder.readSignedInteger(sla::ATTRIB_VAL);
uint4 selectInt = decoder.readSignedInteger(sla::ATTRIB_S);
if (selectInt > v_offset_plus)
throw DecoderError("Bad handle selector encoding");
select = (v_field)selectInt;
if (select == v_offset_plus) {
value_real = decoder.readUnsignedInteger(sla::ATTRIB_PLUS);
}
}
else if (el == sla::ELEM_CONST_START) {
type = j_start;
}
else if (el == sla::ELEM_CONST_NEXT) {
type = j_next;
}
else if (el == sla::ELEM_CONST_NEXT2) {
type = j_next2;
}
else if (el == sla::ELEM_CONST_CURSPACE) {
type = j_curspace;
}
else if (el == sla::ELEM_CONST_CURSPACE_SIZE) {
type = j_curspace_size;
}
else if (el == sla::ELEM_CONST_SPACEID) {
type = spaceid;
value.spaceid = decoder.readSpace(sla::ATTRIB_SPACE);
}
else if (el == sla::ELEM_CONST_RELATIVE) {
type = j_relative;
value_real = decoder.readUnsignedInteger(sla::ATTRIB_VAL);
}
else if (el == sla::ELEM_CONST_FLOWREF) {
type = j_flowref;
}
else if (el == sla::ELEM_CONST_FLOWREF_SIZE) {
type = j_flowref_size;
}
else if (el == sla::ELEM_CONST_FLOWDEST) {
type = j_flowdest;
}
else if (el == sla::ELEM_CONST_FLOWDEST_SIZE) {
type = j_flowdest_size;
}
else
throw LowlevelError("Bad constant type");
decoder.closeElement(el);
}
VarnodeTpl::VarnodeTpl(int4 hand,bool zerosize) :
space(ConstTpl::handle,hand,ConstTpl::v_space), offset(ConstTpl::handle,hand,ConstTpl::v_offset), size(ConstTpl::handle,hand,ConstTpl::v_size)
{ // Varnode built from a handle
// if zerosize is true, set the size constant to zero
if (zerosize)
size = ConstTpl(ConstTpl::real,0);
unnamed_flag = false;
}
VarnodeTpl::VarnodeTpl(const ConstTpl &sp,const ConstTpl &off,const ConstTpl &sz) :
space(sp), offset(off), size(sz)
{
unnamed_flag = false;
}
VarnodeTpl::VarnodeTpl(const VarnodeTpl &vn)
: space(vn.space), offset(vn.offset), size(vn.size)
{ // A clone of the VarnodeTpl
unnamed_flag = vn.unnamed_flag;
}
bool VarnodeTpl::isLocalTemp(void) const
{
if (space.getType() != ConstTpl::spaceid) return false;
if (space.getSpace()->getType()!=IPTR_INTERNAL) return false;
return true;
}
bool VarnodeTpl::isDynamic(const ParserWalker &walker) const
{
if (offset.getType()!=ConstTpl::handle) return false;
// Technically we should probably check all three
// ConstTpls for dynamic handles, but in all cases
// if there is any dynamic piece then the offset is
const FixedHandle &hand(walker.getFixedHandle(offset.getHandleIndex()));
return (hand.offset_space != (AddrSpace *)0);
}
int4 VarnodeTpl::transfer(const vector<HandleTpl *> &params)
{
bool doesOffsetPlus = false;
int4 handleIndex;
int4 plus;
if ((offset.getType() == ConstTpl::handle)&&(offset.getSelect()==ConstTpl::v_offset_plus)) {
handleIndex = offset.getHandleIndex();
plus = (int4)offset.getReal();
doesOffsetPlus = true;
}
space.transfer(params);
offset.transfer(params);
size.transfer(params);
if (doesOffsetPlus) {
if (isLocalTemp())
return plus; // A positive number indicates truncation of a local temp
if (params[handleIndex]->getSize().isZero())
return plus; // or a zerosize object
}
return -1;
}
void VarnodeTpl::changeHandleIndex(const vector<int4> &handmap)
{
space.changeHandleIndex(handmap);
offset.changeHandleIndex(handmap);
size.changeHandleIndex(handmap);
}
bool VarnodeTpl::adjustTruncation(int4 sz,bool isbigendian)
{ // We know this->offset is an offset_plus, check that the truncation is in bounds (given -sz-)
// adjust plus for endianness if necessary
// return true if truncation is in bounds
if (size.getType() != ConstTpl::real)
return false;
int4 numbytes = (int4) size.getReal();
int4 byteoffset = (int4) offset.getReal();
if (numbytes + byteoffset > sz) return false;
// Encode the original truncation amount with the plus value
uintb val = byteoffset;
val <<= 16;
if (isbigendian) {
val |= (uintb)(sz - (numbytes+byteoffset));
}
else {
val |= (uintb) byteoffset;
}
offset = ConstTpl(ConstTpl::handle,offset.getHandleIndex(),ConstTpl::v_offset_plus,val);
return true;
}
void VarnodeTpl::encode(Encoder &encoder) const
{
encoder.openElement(sla::ELEM_VARNODE_TPL);
space.encode(encoder);
offset.encode(encoder);
size.encode(encoder);
encoder.closeElement(sla::ELEM_VARNODE_TPL);
}
void VarnodeTpl::decode(Decoder &decoder)
{
uint4 el = decoder.openElement(sla::ELEM_VARNODE_TPL);
space.decode(decoder);
offset.decode(decoder);
size.decode(decoder);
decoder.closeElement(el);
}
bool VarnodeTpl::operator<(const VarnodeTpl &op2) const
{
if (!(space==op2.space)) return (space<op2.space);
if (!(offset==op2.offset)) return (offset<op2.offset);
if (!(size==op2.size)) return (size<op2.size);
return false;
}
HandleTpl::HandleTpl(const VarnodeTpl *vn)
{ // Build handle which indicates given varnode
space = vn->getSpace();
size = vn->getSize();
ptrspace = ConstTpl(ConstTpl::real,0);
ptroffset = vn->getOffset();
}
HandleTpl::HandleTpl(const ConstTpl &spc,const ConstTpl &sz,const VarnodeTpl *vn,
AddrSpace *t_space,uintb t_offset) :
space(spc), size(sz), ptrspace(vn->getSpace()), ptroffset(vn->getOffset()), ptrsize(vn->getSize()),
temp_space(t_space), temp_offset(ConstTpl::real,t_offset)
{ // Build handle to thing being pointed at by -vn-
}
void HandleTpl::fix(FixedHandle &hand,const ParserWalker &walker) const
{
if (ptrspace.getType() == ConstTpl::real) {
// The export is unstarred, but this doesn't mean the varnode
// being exported isn't dynamic
space.fillinSpace(hand,walker);
hand.size = size.fix(walker);
ptroffset.fillinOffset(hand,walker);
}
else {
hand.space = space.fixSpace(walker);
hand.size = size.fix(walker);
hand.offset_offset = ptroffset.fix(walker);
hand.offset_space = ptrspace.fixSpace(walker);
if (hand.offset_space->getType()==IPTR_CONSTANT) {
// Handle could have been dynamic but wasn't
hand.offset_space = (AddrSpace *)0;
hand.offset_offset = AddrSpace::addressToByte(hand.offset_offset,hand.space->getWordSize());
hand.offset_offset = hand.space->wrapOffset(hand.offset_offset);
}
else {
hand.offset_size = ptrsize.fix(walker);
hand.temp_space = temp_space.fixSpace(walker);
hand.temp_offset = temp_offset.fix(walker);
}
}
}
void HandleTpl::changeHandleIndex(const vector<int4> &handmap)
{
space.changeHandleIndex(handmap);
size.changeHandleIndex(handmap);
ptrspace.changeHandleIndex(handmap);
ptroffset.changeHandleIndex(handmap);
ptrsize.changeHandleIndex(handmap);
temp_space.changeHandleIndex(handmap);
temp_offset.changeHandleIndex(handmap);
}
void HandleTpl::encode(Encoder &encoder) const
{
encoder.openElement(sla::ELEM_HANDLE_TPL);
space.encode(encoder);
size.encode(encoder);
ptrspace.encode(encoder);
ptroffset.encode(encoder);
ptrsize.encode(encoder);
temp_space.encode(encoder);
temp_offset.encode(encoder);
encoder.closeElement(sla::ELEM_HANDLE_TPL);
}
void HandleTpl::decode(Decoder &decoder)
{
uint4 el = decoder.openElement(sla::ELEM_HANDLE_TPL);
space.decode(decoder);
size.decode(decoder);
ptrspace.decode(decoder);
ptroffset.decode(decoder);
ptrsize.decode(decoder);
temp_space.decode(decoder);
temp_offset.decode(decoder);
decoder.closeElement(el);
}
OpTpl::~OpTpl(void)
{ // An OpTpl owns its varnode_tpls
if (output != (VarnodeTpl *)0)
delete output;
vector<VarnodeTpl *>::iterator iter;
for(iter=input.begin();iter!=input.end();++iter)
delete *iter;
}
bool OpTpl::isZeroSize(void) const
{ // Return if any input or output has zero size
vector<VarnodeTpl *>::const_iterator iter;
if (output != (VarnodeTpl *)0)
if (output->isZeroSize()) return true;
for(iter=input.begin();iter!=input.end();++iter)
if ((*iter)->isZeroSize()) return true;
return false;
}
void OpTpl::removeInput(int4 index)
{ // Remove the indicated input
delete input[index];
for(int4 i=index;i<input.size()-1;++i)
input[i] = input[i+1];
input.pop_back();
}
void OpTpl::changeHandleIndex(const vector<int4> &handmap)
{
if (output != (VarnodeTpl *)0)
output->changeHandleIndex(handmap);
vector<VarnodeTpl *>::const_iterator iter;
for(iter=input.begin();iter!=input.end();++iter)
(*iter)->changeHandleIndex(handmap);
}
void OpTpl::encode(Encoder &encoder) const
{
encoder.openElement(sla::ELEM_OP_TPL);
encoder.writeOpcode(sla::ATTRIB_CODE, opc);
if (output == (VarnodeTpl *)0) {
encoder.openElement(sla::ELEM_NULL);
encoder.closeElement(sla::ELEM_NULL);
}
else
output->encode(encoder);
for(int4 i=0;i<input.size();++i)
input[i]->encode(encoder);
encoder.closeElement(sla::ELEM_OP_TPL);
}
void OpTpl::decode(Decoder &decoder)
{
uint4 el = decoder.openElement(sla::ELEM_OP_TPL);
opc = decoder.readOpcode(sla::ATTRIB_CODE);
uint4 subel = decoder.peekElement();
if (subel == sla::ELEM_NULL) {
decoder.openElement();
decoder.closeElement(subel);
output = (VarnodeTpl *)0;
}
else {
output = new VarnodeTpl();
output->decode(decoder);
}
while(decoder.peekElement() != 0) {
VarnodeTpl *vn = new VarnodeTpl();
vn->decode(decoder);
input.push_back(vn);
}
decoder.closeElement(el);
}
ConstructTpl::~ConstructTpl(void)
{ // Constructor owns its ops and handles
vector<OpTpl *>::iterator oiter;
for(oiter=vec.begin();oiter!=vec.end();++oiter)
delete *oiter;
if (result != (HandleTpl *)0)
delete result;
}
bool ConstructTpl::addOp(OpTpl *ot)
{
if (ot->getOpcode() == DELAY_SLOT) {
if (delayslot != 0)
return false; // Cannot have multiple delay slots
delayslot = ot->getIn(0)->getOffset().getReal();
}
else if (ot->getOpcode() == LABELBUILD)
numlabels += 1; // Count labels
vec.push_back(ot);
return true;
}
bool ConstructTpl::addOpList(const vector<OpTpl *> &oplist)
{
for(int4 i=0;i<oplist.size();++i)
if (!addOp(oplist[i]))
return false;
return true;
}
int4 ConstructTpl::fillinBuild(vector<int4> &check,AddrSpace *const_space)
{ // Make sure there is a build statement for all subtable params
// Return 0 upon success, 1 if there is a duplicate BUILD, 2 if there is a build for a non-subtable
vector<OpTpl *>::iterator iter;
OpTpl *op;
VarnodeTpl *indvn;
for(iter=vec.begin();iter!=vec.end();++iter) {
op = *iter;
if (op->getOpcode() == BUILD) {
int4 index = op->getIn(0)->getOffset().getReal();
if (check[index] != 0)
return check[index]; // Duplicate BUILD statement or non-subtable
check[index] = 1; // Mark to avoid future duplicate build
}
}
for(int4 i=0;i<check.size();++i) {
if (check[i] == 0) { // Didn't see a BUILD statement
op = new OpTpl(BUILD);
indvn = new VarnodeTpl(ConstTpl(const_space),
ConstTpl(ConstTpl::real,i),
ConstTpl(ConstTpl::real,4));
op->addInput(indvn);
vec.insert(vec.begin(),op);
}
}
return 0;
}
bool ConstructTpl::buildOnly(void) const
{
vector<OpTpl *>::const_iterator iter;
OpTpl *op;
for(iter=vec.begin();iter!=vec.end();++iter) {
op = *iter;
if (op->getOpcode() != BUILD)
return false;
}
return true;
}
void ConstructTpl::changeHandleIndex(const vector<int4> &handmap)
{
vector<OpTpl *>::const_iterator iter;
OpTpl *op;
for(iter=vec.begin();iter!=vec.end();++iter) {
op = *iter;
if (op->getOpcode() == BUILD) {
int4 index = op->getIn(0)->getOffset().getReal();
index = handmap[index];
op->getIn(0)->setOffset(index);
}
else
op->changeHandleIndex(handmap);
}
if (result != (HandleTpl *)0)
result->changeHandleIndex(handmap);
}
void ConstructTpl::setInput(VarnodeTpl *vn,int4 index,int4 slot)
{ // set the VarnodeTpl input for a particular op
// for use with optimization routines
OpTpl *op = vec[index];
VarnodeTpl *oldvn = op->getIn(slot);
op->setInput(vn,slot);
if (oldvn != (VarnodeTpl *)0)
delete oldvn;
}
void ConstructTpl::setOutput(VarnodeTpl *vn,int4 index)
{ // set the VarnodeTpl output for a particular op
// for use with optimization routines
OpTpl *op = vec[index];
VarnodeTpl *oldvn = op->getOut();
op->setOutput(vn);
if (oldvn != (VarnodeTpl *)0)
delete oldvn;
}
void ConstructTpl::deleteOps(const vector<int4> &indices)
{ // delete a particular set of ops
for(uint4 i=0;i<indices.size();++i) {
delete vec[indices[i]];
vec[indices[i]] = (OpTpl *)0;
}
uint4 poscur = 0;
for(uint4 i=0;i<vec.size();++i) {
OpTpl *op = vec[i];
if (op != (OpTpl *)0) {
vec[poscur] = op;
poscur += 1;
}
}
while(vec.size() > poscur)
vec.pop_back();
}
void ConstructTpl::encode(Encoder &encoder,int4 sectionid) const
{
encoder.openElement(sla::ELEM_CONSTRUCT_TPL);
if (sectionid >=0 )
encoder.writeSignedInteger(sla::ATTRIB_SECTION, sectionid);
if (delayslot != 0)
encoder.writeSignedInteger(sla::ATTRIB_DELAY, delayslot);
if (numlabels != 0)
encoder.writeSignedInteger(sla::ATTRIB_LABELS, numlabels);
if (result != (HandleTpl *)0)
result->encode(encoder);
else {
encoder.openElement(sla::ELEM_NULL);
encoder.closeElement(sla::ELEM_NULL);
}
for(int4 i=0;i<vec.size();++i)
vec[i]->encode(encoder);
encoder.closeElement(sla::ELEM_CONSTRUCT_TPL);
}
int4 ConstructTpl::decode(Decoder &decoder)
{
uint4 el = decoder.openElement(sla::ELEM_CONSTRUCT_TPL);
int4 sectionid = -1;
uint4 attrib = decoder.getNextAttributeId();
while(attrib != 0) {
if (attrib == sla::ATTRIB_DELAY) {
delayslot = decoder.readSignedInteger();
}
else if (attrib == sla::ATTRIB_LABELS) {
numlabels = decoder.readSignedInteger();
}
else if (attrib == sla::ATTRIB_SECTION) {
sectionid = decoder.readSignedInteger();
}
attrib = decoder.getNextAttributeId();
}
uint4 subel = decoder.peekElement();
if (subel == sla::ELEM_NULL) {
decoder.openElement();
decoder.closeElement(subel);
result = (HandleTpl *)0;
}
else {
result = new HandleTpl();
result->decode(decoder);
}
while(decoder.peekElement() != 0) {
OpTpl *op = new OpTpl();
op->decode(decoder);
vec.push_back(op);
}
decoder.closeElement(el);
return sectionid;
}
void PcodeBuilder::build(ConstructTpl *construct,int4 secnum)
{
if (construct == (ConstructTpl *)0)
throw UnimplError("",0); // Pcode is not implemented for this constructor
uint4 oldbase = labelbase; // Recursively store old labelbase
labelbase = labelcount; // Set the newbase
labelcount += construct->numLabels(); // Add labels from this template
vector<OpTpl *>::const_iterator iter;
OpTpl *op;
const vector<OpTpl *> &ops(construct->getOpvec());
for(iter=ops.begin();iter!=ops.end();++iter) {
op = *iter;
switch(op->getOpcode()) {
case BUILD:
appendBuild( op, secnum );
break;
case DELAY_SLOT:
delaySlot( op );
break;
case LABELBUILD:
setLabel( op );
break;
case CROSSBUILD:
appendCrossBuild(op,secnum);
break;
default:
dump( op );
break;
}
}
labelbase = oldbase; // Restore old labelbase
}
} // End namespace ghidra