/* ###
 * 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 "funcdata.hh"

namespace ghidra {

// Funcdata members pertaining directly to varnodes

/// Properties of a given storage location are gathered from symbol information and
/// applied to the given Varnode.
/// \param vn is the given Varnode
void Funcdata::setVarnodeProperties(Varnode *vn) const

{
  if (!vn->isMapped()) {
  // One more chance to find entry, now that we know usepoint
    uint4 vflags=0;
    SymbolEntry *entry = localmap->queryProperties(vn->getAddr(),vn->getSize(),vn->getUsePoint(*this),vflags);
    if (entry != (SymbolEntry *)0) // Let entry try to force type
      vn->setSymbolProperties(entry);
    else
      vn->setFlags(vflags & ~Varnode::typelock); // typelock set by updateType
  }

  if (vn->cover == (Cover *)0) {
    if (isHighOn())
      vn->calcCover();
  }
}

/// If HighVariables are enabled, make sure the given Varnode has one assigned. Allocate
/// a dedicated HighVariable, that contains only the one Varnode if necessary.
/// \param vn is the given Varnode
/// \return the assigned HighVariable or NULL if one is not assigned
HighVariable *Funcdata::assignHigh(Varnode *vn)

{
  if ((flags & highlevel_on)!=0) {
    if (vn->hasCover())
      vn->calcCover();
    if (!vn->isAnnotation()) {
      return new HighVariable(vn);
    }
  }
  return (HighVariable *)0;
}

/// A Varnode is allocated which represents the indicated constant value.
/// Its storage address is in the \e constant address space.
/// \param s is the size of the Varnode in bytes
/// \param constant_val is the indicated constant value
/// \return the new Varnode object
Varnode *Funcdata::newConstant(int4 s,uintb constant_val)

{
  Datatype *ct = glb->types->getBase(s,TYPE_UNKNOWN);

  Varnode *vn = vbank.create(s,glb->getConstant(constant_val),ct);
  assignHigh(vn);

				// There is no chance of matching localmap
  return vn;
}

/// A new temporary register storage location is allocated from the \e unique
/// address space
/// \param s is the size of the Varnode in bytes
/// \param ct is an optional data-type to associated with the Varnode
/// \return the newly allocated \e temporary Varnode
Varnode *Funcdata::newUnique(int4 s,Datatype *ct)

{
  if (ct == (Datatype *)0)
    ct = glb->types->getBase(s,TYPE_UNKNOWN);
  Varnode *vn = vbank.createUnique(s,ct);
  assignHigh(vn);
  if (s >= minLanedSize)
    checkForLanedRegister(s, vn->getAddr());

				// No chance of matching localmap
  return vn;
}

/// Create a new Varnode which is already defined as output of a given PcodeOp.
/// This if more efficient as it avoids the initial insertion of the free form of the
/// Varnode into the tree, and queryProperties only needs to be called once.
/// \param s is the size of the new Varnode in bytes
/// \param m is the storage Address of the Varnode
/// \param op is the given PcodeOp whose output is created
/// \return the new Varnode object
Varnode *Funcdata::newVarnodeOut(int4 s,const Address &m,PcodeOp *op)

{
  Datatype *ct = glb->types->getBase(s,TYPE_UNKNOWN);
  Varnode *vn = vbank.createDef(s,m,ct,op);
  op->setOutput(vn);
  assignHigh(vn);

  if (s >= minLanedSize)
    checkForLanedRegister(s,m);
  uint4 vflags = 0;
  SymbolEntry *entry = localmap->queryProperties(m,s,op->getAddr(),vflags);
  if (entry != (SymbolEntry *)0)
    vn->setSymbolProperties(entry);
  else
    vn->setFlags(vflags & ~Varnode::typelock); // Typelock set by updateType

  return vn;
}

/// Allocate a new register from the \e unique address space and create a new
/// Varnode object representing it as an output to the given PcodeOp
/// \param s is the size of the new Varnode in bytes
/// \param op is the given PcodeOp whose output is created
/// \return the new temporary register Varnode
Varnode *Funcdata::newUniqueOut(int4 s,PcodeOp *op)

{
  Datatype *ct = glb->types->getBase(s,TYPE_UNKNOWN);
  Varnode *vn = vbank.createDefUnique(s,ct,op);
  op->setOutput(vn);
  assignHigh(vn);
  if (s >= minLanedSize)
    checkForLanedRegister(s, vn->getAddr());
  // No chance of matching localmap
  return vn;
}

/// \brief Create a new unattached Varnode object
///
/// \param s is the size of the new Varnode in bytes
/// \param m is the storage Address of the Varnode
/// \param ct is a data-type to associate with the Varnode
/// \return the newly allocated Varnode object
Varnode *Funcdata::newVarnode(int4 s,const Address &m,Datatype *ct)

{
  Varnode *vn;

  if (ct == (const Datatype *)0)
    ct = glb->types->getBase(s,TYPE_UNKNOWN);

  vn = vbank.create(s,m,ct);
  assignHigh(vn);

  if (s >= minLanedSize)
    checkForLanedRegister(s,m);
  uint4 vflags=0;
  SymbolEntry *entry = localmap->queryProperties(vn->getAddr(),vn->getSize(),Address(),vflags);
  if (entry != (SymbolEntry *)0)	// Let entry try to force type
    vn->setSymbolProperties(entry);
  else
    vn->setFlags(vflags & ~Varnode::typelock); // Typelock set by updateType

  return vn;
}

/// Create a special \e annotation Varnode that holds a pointer reference to a specific
/// PcodeOp.  This is used specifically to let a CPUI_INDIRECT op refer to the PcodeOp
/// it is holding an indirect effect for.
/// \param op is the PcodeOp to encode in the annotation
/// \return the newly allocated \e annotation Varnode
Varnode *Funcdata::newVarnodeIop(PcodeOp *op)

{
  Datatype *ct = glb->types->getBase(sizeof(op),TYPE_UNKNOWN);
  AddrSpace *cspc = glb->getIopSpace();
  Varnode *vn = vbank.create(sizeof(op),Address(cspc,(uintb)(uintp)op),ct);
  assignHigh(vn);
  return vn;
}

/// A reference to a particular address space is encoded as a constant Varnode.
/// These are used for LOAD and STORE p-code ops in particular.
/// \param spc is the address space to encode
/// \return the newly allocated constant Varnode
Varnode *Funcdata::newVarnodeSpace(AddrSpace *spc)

{
  Datatype *ct = glb->types->getBase(sizeof(spc),TYPE_UNKNOWN);

  Varnode *vn = vbank.create(sizeof(spc),glb->createConstFromSpace(spc),ct);
  assignHigh(vn);
  return vn;
}

/// A call specification (FuncCallSpecs) is encoded into an \e annotation Varnode.
/// The Varnode is used specifically as an input to CPUI_CALL ops to speed up access
/// to their associated call specification.
/// \param fc is the call specification to encode
/// \return the newly allocated \e annotation Varnode
Varnode *Funcdata::newVarnodeCallSpecs(FuncCallSpecs *fc)

{
  Datatype *ct = glb->types->getBase(sizeof(fc),TYPE_UNKNOWN);

  AddrSpace *cspc = glb->getFspecSpace();
  Varnode *vn = vbank.create(sizeof(fc),Address(cspc,(uintb)(uintp)fc),ct);
  assignHigh(vn);
  return vn;
}

/// A reference to a specific Address is encoded in a Varnode.  The Varnode is
/// an \e annotation in the sense that it will hold no value in the data-flow, it will
/// will only hold a reference to an address. This is used specifically by the branch
/// p-code operations to hold destination addresses.
/// \param m is the Address to encode
/// \return the newly allocated \e annotation Varnode
Varnode *Funcdata::newCodeRef(const Address &m)

{
  Varnode *vn;
  Datatype *ct;

  ct = glb->types->getTypeCode();
  vn = vbank.create(1,m,ct);
  vn->setFlags(Varnode::annotation);
  assignHigh(vn);
  return vn;
}

/// \param s is the size of the Varnode in bytes
/// \param base is the address space of the Varnode
/// \param off is the offset into the address space of the Varnode
/// \return the newly allocated Varnode
Varnode *Funcdata::newVarnode(int4 s,AddrSpace *base,uintb off)

{
  Varnode *vn;

  vn = newVarnode(s,Address(base,off));

  return vn;
}

/// Internal factory for copying Varnodes from another Funcdata object into \b this.
/// \param vn is the Varnode to clone
/// \return the cloned Varnode (contained by \b this)
Varnode *Funcdata::cloneVarnode(const Varnode *vn)

{
  Varnode *newvn;

  newvn = vbank.create(vn->getSize(),vn->getAddr(),vn->getType());
  uint4 vflags = vn->getFlags();
  // These are the flags we allow to be cloned
  vflags &= (Varnode::annotation | Varnode::externref |
	     Varnode::readonly | Varnode::persist |
	     Varnode::addrtied | Varnode::addrforce |
	     Varnode::indirect_creation | Varnode::incidental_copy |
	     Varnode::volatil | Varnode::mapped);
  newvn->setFlags(vflags);
  return newvn;
}

/// References to the Varnode are replaced with NULL pointers and the object is freed,
/// with no possibility of resuse.
/// \param vn is the Varnode to delete
void Funcdata::destroyVarnode(Varnode *vn)

{
  list<PcodeOp *>::const_iterator iter;

  for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
    PcodeOp *op = *iter;
#ifdef OPACTION_DEBUG
    if (opactdbg_active)
      debugModCheck(op);
#endif
    op->clearInput(op->getSlot(vn));
  }
  if (vn->def != (PcodeOp *)0) {
    vn->def->setOutput((Varnode *)0);
    vn->def = (PcodeOp *)0;
  }

  vn->destroyDescend();
  vbank.destroy(vn);
}

/// Check if the given storage range is a potential laned register.
/// If so, record the storage with the matching laned register record.
/// \param sz is the size of the storage range in bytes
/// \param addr is the starting address of the storage range
void Funcdata::checkForLanedRegister(int4 sz,const Address &addr)

{
  const LanedRegister *lanedRegister  = glb->getLanedRegister(addr,sz);
  if (lanedRegister == (const LanedRegister *)0)
    return;
  VarnodeData storage;
  storage.space = addr.getSpace();
  storage.offset = addr.getOffset();
  storage.size = sz;
  lanedMap[storage] = lanedRegister;
}

/// Look up the Symbol visible in \b this function's Scope and return the HighVariable
/// associated with it.  If the Symbol doesn't exist or there is no Varnode holding at least
/// part of the value of the Symbol, NULL is returned.
/// \param nm is the name to search for
/// \return the matching HighVariable or NULL
HighVariable *Funcdata::findHigh(const string &nm) const

{
  vector<Symbol *> symList;
  localmap->queryByName(nm,symList);
  if (symList.empty()) return (HighVariable *)0;
  Symbol *sym = symList[0];
  Varnode *vn = findLinkedVarnode(sym->getFirstWholeMap());
  if (vn != (Varnode *)0)
    return vn->getHigh();

  return (HighVariable *)0;
}

/// An \e input Varnode has a special designation within SSA form as not being defined
/// by a p-code operation and is a formal input to the data-flow of the function.  It is
/// not necessarily a formal function parameter.
///
/// The given Varnode to be marked is also returned unless there is an input Varnode that
/// already exists which overlaps the given Varnode.  If the Varnodes have the same size and
/// storage address, the preexisting input Varnode is returned instead. Otherwise an
/// exception is thrown.
/// \param vn is the given Varnode to mark as an input
/// \return the marked Varnode
Varnode *Funcdata::setInputVarnode(Varnode *vn)

{
  Varnode *invn;

  if (vn->isInput()) return vn;	// Already an input
				// First we check if it overlaps any other varnode
  VarnodeDefSet::const_iterator iter;
  iter = vbank.beginDef(Varnode::input,vn->getAddr()+vn->getSize());

  // Iter points at first varnode AFTER vn
  if (iter != vbank.beginDef()) {
    --iter;			// previous varnode
    invn = *iter;	  	// comes before vn or intersects
    if (invn->isInput()) {
      if ((-1 != vn->overlap(*invn))||(-1 != invn->overlap(*vn))) {
	if ((vn->getSize() == invn->getSize())&&(vn->getAddr() == invn->getAddr()))
	  return invn;
	throw LowlevelError("Overlapping input varnodes");
      }
    }
  }

  vn = vbank.setInput(vn);
  setVarnodeProperties(vn);
  uint4 effecttype = funcp.hasEffect(vn->getAddr(),vn->getSize());
  if (effecttype == EffectRecord::unaffected)
    vn->setUnaffected();
  if (effecttype == EffectRecord::return_address) {
    vn->setUnaffected();	// Should be unaffected over the course of the function
    vn->setReturnAddress();
  }
  return vn;
}

/// \brief Adjust input Varnodes contained in the given range
///
/// After this call, a single \e input Varnode will exist that fills the given range.
/// Any previous input Varnodes contained in this range are redefined using a SUBPIECE
/// op off of the new single input.  If an overlapping Varnode isn't fully contained
/// an exception is thrown.
/// \param addr is the starting address of the range
/// \param sz is the number of bytes in the range
void Funcdata::adjustInputVarnodes(const Address &addr,int4 sz)

{
  Address endaddr = addr + (sz-1);
  vector<Varnode *> inlist;
  VarnodeDefSet::const_iterator iter,enditer;
  iter = vbank.beginDef(Varnode::input,addr);
  enditer = vbank.endDef(Varnode::input,endaddr);
  while(iter != enditer) {
    Varnode *vn = *iter;
    ++iter;
    if (vn->getOffset() + (vn->getSize()-1) > endaddr.getOffset())
      throw LowlevelError("Cannot properly adjust input varnodes");
    inlist.push_back(vn);
  }

  for(uint4 i=0;i<inlist.size();++i) {
    Varnode *vn = inlist[i];
    int4 sa = addr.justifiedContain(sz,vn->getAddr(),vn->getSize(),false);
    if ((!vn->isInput())||(sa < 0)||(sz<=vn->getSize()))
      throw LowlevelError("Bad adjustment to input varnode");
    PcodeOp *subop = newOp(2,getAddress());
    opSetOpcode(subop,CPUI_SUBPIECE);
    opSetInput(subop,newConstant(4,sa),1);
    Varnode *newvn = newVarnodeOut(vn->getSize(),vn->getAddr(),subop);
    // newvn must not be free in order to give all vn's descendants
    opInsertBegin(subop,(BlockBasic *)bblocks.getBlock(0));
    totalReplace(vn,newvn);
    deleteVarnode(vn); // Get rid of old input before creating new input
    inlist[i] = newvn;
  }
  // Now that all the intersecting inputs have been pulled out, we can create the new input
  Varnode *invn = newVarnode(sz,addr);
  invn = setInputVarnode(invn);
  // The new input may cause new heritage and "Heritage AFTER dead removal" errors
  // So tell heritage to ignore it
  // FIXME: It would probably be better to insert this directly into heritage's globaldisjoint
  invn->setWriteMask();
  // Now change all old inputs to be created as SUBPIECE from the new input
  for(uint4 i=0;i<inlist.size();++i) {
    PcodeOp *op = inlist[i]->getDef();
    opSetInput(op,invn,0);
  }
}

/// All p-code ops that read the Varnode are transformed so that they read
/// a special constant instead (associate with unreachable block removal).
/// \param vn is the given Varnode
/// \return \b true if a PcodeOp is modified
bool Funcdata::descend2Undef(Varnode *vn)

{
  PcodeOp *op,*copyop;
  BlockBasic *inbl;
  Varnode *badconst;
  list<PcodeOp *>::const_iterator iter;
  int4 i,sz;
  bool res;

  res = false;
  sz = vn->getSize();
  iter = vn->beginDescend();
  while(iter != vn->endDescend()) {
    op = *iter++;		// Move to next in list before deletion
    if (op->getParent()->isDead()) continue;
    if (op->getParent()->sizeIn()!=0) res = true;
    i = op->getSlot(vn);
    badconst = newConstant(sz,0xBADDEF);
    if (op->code()==CPUI_MULTIEQUAL) { // Cannot put constant directly into MULTIEQUAL
      inbl = (BlockBasic *) op->getParent()->getIn(i);
      copyop = newOp(1,inbl->getStart());
      Varnode *inputvn = newUniqueOut(sz,copyop);
      opSetOpcode(copyop,CPUI_COPY);
      opSetInput(copyop,badconst,0);
      opInsertEnd(copyop,inbl);
      opSetInput(op,inputvn,i);
    }
    else if (op->code()==CPUI_INDIRECT) { // Cannot put constant directly into INDIRECT
      copyop = newOp(1,op->getAddr());
      Varnode *inputvn = newUniqueOut(sz,copyop);
      opSetOpcode(copyop,CPUI_COPY);
      opSetInput(copyop,badconst,0);
      opInsertBefore(copyop,op);
      opSetInput(op,inputvn,i);
    }
    else
      opSetInput(op,badconst,i);
  }
  return res;
}

void Funcdata::initActiveOutput(void)

{
  activeoutput = new ParamActive(false);
  int4 maxdelay = funcp.getMaxOutputDelay();
  if (maxdelay > 0)
    maxdelay = 3;
  activeoutput->setMaxPass(maxdelay);
}

void Funcdata::setHighLevel(void)

{
  if ((flags & highlevel_on)!=0) return;
  flags |= highlevel_on;
  high_level_index = vbank.getCreateIndex();
  VarnodeLocSet::const_iterator iter;

  for(iter=vbank.beginLoc();iter!=vbank.endLoc();++iter)
    assignHigh(*iter);
}

/// \brief Copy properties from an existing Varnode to a new Varnode
///
/// The new Varnode is assumed to overlap the storage of the existing Varnode.
/// Properties like boolean flags and \e consume bits are copied as appropriate.
/// \param vn is the existing Varnode
/// \param newVn is the new Varnode that has its properties set
/// \param lsbOffset is the significance offset of the new Varnode within the exising
void Funcdata::transferVarnodeProperties(Varnode *vn,Varnode *newVn,int4 lsbOffset)

{
  uintb newConsume = (vn->getConsume() >> 8*lsbOffset) & calc_mask(newVn->getSize());

  uint4 vnFlags = vn->getFlags() & (Varnode::directwrite|Varnode::addrforce);

  newVn->setFlags(vnFlags);	// Preserve addrforce setting
  newVn->setConsume(newConsume);
}

/// Treat the given Varnode as read-only, look up its value in LoadImage
/// and replace read references with the value as a constant Varnode.
/// \param vn is the given Varnode
/// \return \b true if any change was made
bool Funcdata::fillinReadOnly(Varnode *vn)

{
  if (vn->isWritten()) {	// Can't replace output with constant
    PcodeOp *defop = vn->getDef();
    if (defop->isMarker())
      defop->setAdditionalFlag(PcodeOp::warning);	// Not a true write, ignore it
    else if (!defop->isWarning()) { // No warning generated before
      defop->setAdditionalFlag(PcodeOp::warning);
      ostringstream s;
      if ((!vn->isAddrForce())||(!vn->hasNoDescend())) {
	s << "Read-only address (";
	s << vn->getSpace()->getName();
	s << ',';
	vn->getAddr().printRaw(s);
	s << ") is written";
	warning(s.str(),defop->getAddr());
      }
    }
    return false;		// No change was made
  }

  if (vn->getSize() > sizeof(uintb))
    return false;		// Constant will exceed precision

  uintb res;
  uint1 bytes[32];
  try {
    glb->loader->loadFill(bytes,vn->getSize(),vn->getAddr());
  } catch(DataUnavailError &err) { // Could not get value from LoadImage
    vn->clearFlags(Varnode::readonly); // Treat as writeable
    return true;
  }

  if (vn->getSpace()->isBigEndian()) { // Big endian
    res = 0;
    for(int4 i=0;i<vn->getSize();++i) {
      res <<= 8;
      res |= bytes[i];
    }
  }
  else {
    res = 0;
    for(int4 i=vn->getSize()-1;i>=0;--i) {
      res <<= 8;
      res |= bytes[i];
    }
  }
				// Replace all references to vn
  bool changemade = false;
  list<PcodeOp *>::const_iterator iter;
  PcodeOp *op;
  int4 i;
  Datatype *locktype = vn->isTypeLock() ? vn->getType() : (Datatype *)0;

  iter = vn->beginDescend();
  while(iter != vn->endDescend()) {
    op = *iter++;
    i = op->getSlot(vn);
    if (op->isMarker()) {		// Must be careful putting constants in here
      if ((op->code()!=CPUI_INDIRECT)||(i!=0)) continue;
      Varnode *outvn = op->getOut();
      if (outvn->getAddr() == vn->getAddr()) continue; // Ignore indirect to itself
      // Change the indirect to a COPY
      opRemoveInput(op,1);
      opSetOpcode(op,CPUI_COPY);
    }
    Varnode *cvn = newConstant(vn->getSize(),res);
    if (locktype != (Datatype *)0)
      cvn->updateType(locktype,true,true); // Try to pass on the locked datatype
    opSetInput(op,cvn,i);
    changemade = true;
  }
  return changemade;
}

/// The Varnode is assumed not fully linked.  The read or write action is
/// modeled by inserting a special \e user op that represents the action. The given Varnode is
/// replaced by a temporary Varnode within the data-flow, and the original address becomes
/// a parameter to the user op.
/// \param vn is the given Varnode to model as volatile
/// \return \b true if a change was made
bool Funcdata::replaceVolatile(Varnode *vn)

{
  PcodeOp *newop;
  if (vn->isWritten()) {	// A written value
    VolatileWriteOp *vw_op = glb->userops.getVolatileWrite();
    if (!vn->hasNoDescend()) throw LowlevelError("Volatile memory was propagated");
    PcodeOp *defop = vn->getDef();
    newop = newOp(3,defop->getAddr());
    opSetOpcode(newop,CPUI_CALLOTHER);
    // Create a userop of type specified by vw_op
    opSetInput(newop,newConstant(4,vw_op->getIndex()),0);
    // The first parameter is the offset of volatile memory location
    Varnode *annoteVn = newCodeRef(vn->getAddr());
    annoteVn->setFlags(Varnode::volatil);
    opSetInput(newop,annoteVn,1);
    // Replace the volatile variable with a temp
    Varnode *tmp = newUnique(vn->getSize());
    opSetOutput(defop,tmp);
    // The temp is the second parameter to the userop
    opSetInput(newop,tmp,2);
    opInsertAfter(newop,defop); // Insert after defining op
  }
  else {			// A read value
    VolatileReadOp *vr_op = glb->userops.getVolatileRead();
    if (vn->hasNoDescend()) return false; // Dead
    PcodeOp *readop = vn->loneDescend();
    if (readop == (PcodeOp *)0)
      throw LowlevelError("Volatile memory value used more than once");
    newop = newOp(2,readop->getAddr());
    opSetOpcode(newop,CPUI_CALLOTHER);
    // Create a temp to replace the volatile variable
    Varnode *tmp = newUniqueOut(vn->getSize(),newop);
    // Create a userop of type specified by vr_op
    opSetInput(newop,newConstant(4,vr_op->getIndex()),0);
    // The first parameter is the offset of the volatile memory loc
    Varnode *annoteVn = newCodeRef(vn->getAddr());
    annoteVn->setFlags(Varnode::volatil);
    opSetInput(newop,annoteVn,1);
    opSetInput(readop,tmp,readop->getSlot(vn));
    opInsertBefore(newop,readop); // Insert before read
    if (vr_op->getDisplay() != 0)	// Unless the display is functional,
      newop->setHoldOutput();		// read value may not be used. Keep it around anyway.
  }
  if (vn->isTypeLock())		// If the original varnode had a type locked on it
    newop->setAdditionalFlag(PcodeOp::special_prop); // Mark this op as doing special propagation
  return true;
}

/// \brief Check if the given Varnode only flows into call-based INDIRECT ops
///
/// Flow is only followed through MULTIEQUAL ops.
/// \param vn is the given Varnode
/// \return \b true if all flows hit an INDIRECT op
bool Funcdata::checkIndirectUse(Varnode *vn)

{
  vector<Varnode *> vlist;
  int4 i = 0;
  vlist.push_back(vn);
  vn->setMark();
  bool result = true;
  while((i<vlist.size())&&result) {
    vn = vlist[i++];
    list<PcodeOp *>::const_iterator iter;
    for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
      PcodeOp *op = *iter;
      OpCode opc = op->code();
      if (opc == CPUI_INDIRECT) {
	if (op->isIndirectStore()) {
	  // INDIRECT from a STORE is not a negative result but continue to follow data-flow
	  Varnode *outvn = op->getOut();
	  if (!outvn->isMark()) {
	    vlist.push_back(outvn);
	    outvn->setMark();
	  }
	}
      }
      else if (opc == CPUI_MULTIEQUAL) {
	Varnode *outvn = op->getOut();
	if (!outvn->isMark()) {
	  vlist.push_back(outvn);
	  outvn->setMark();
	}
      }
      else {
	result = false;
	break;
      }
    }
  }
  for(i=0;i<vlist.size();++i)
    vlist[i]->clearMark();
  return result;
}

/// The illegal inputs are additionally marked as \b indirectonly and
/// isIndirectOnly() returns \b true.
void Funcdata::markIndirectOnly(void)

{
  VarnodeDefSet::const_iterator iter,enditer;

  iter = beginDef(Varnode::input);
  enditer = endDef(Varnode::input);
  for(;iter!=enditer;++iter) {	// Loop over all inputs
    Varnode *vn = *iter;
    if (!vn->isIllegalInput()) continue; // Only check illegal inputs
    if (checkIndirectUse(vn))
      vn->setFlags(Varnode::indirectonly);
  }
}

/// Free any Varnodes not attached to anything. This is only performed at fixed times so that
/// editing operations can detach (and then reattach) Varnodes without losing them.
void Funcdata::clearDeadVarnodes(void)

{
  VarnodeLocSet::const_iterator iter;
  Varnode *vn;

  iter = vbank.beginLoc();
  while(iter!=vbank.endLoc()) {
    vn = *iter++;
    if (vn->hasNoDescend()) {
      if (vn->isInput() && !vn->isLockedInput()) {
	vbank.makeFree(vn);
	vn->clearCover();
      }
      if (vn->isFree())
	vbank.destroy(vn);
    }
  }
}

/// All Varnodes are initialized assuming that all its bits are possibly non-zero. This method
/// looks for situations where a p-code produces a value that is known to have some bits that are
/// guaranteed to be zero.  It updates the state of the output Varnode then tries to push the
/// information forward through the data-flow until additional changes are apparent.
void Funcdata::calcNZMask(void)

{
  vector<PcodeOpNode> opstack;
  list<PcodeOp *>::const_iterator oiter;

  for(oiter=beginOpAlive();oiter!=endOpAlive();++oiter) {
    PcodeOp *op = *oiter;
    if (op->isMark()) continue;
    opstack.push_back(PcodeOpNode(op,0));
    op->setMark();

    do {
      // Get next edge
      PcodeOpNode &node( opstack.back() );
      if (node.slot >= node.op->numInput()) { // If no edge left
	Varnode *outvn = node.op->getOut();
	if (outvn != (Varnode *)0) {
	  outvn->nzm = node.op->getNZMaskLocal(true);
	}
	opstack.pop_back();	// Pop a level
	continue;
      }
      int4 oldslot = node.slot;
      node.slot += 1; // Advance to next input
      // Determine if we want to traverse this edge
      if (node.op->code() == CPUI_MULTIEQUAL) {
	if (node.op->getParent()->isLoopIn(oldslot)) // Clip looping edges
	  continue;
      }
      // Traverse edge indicated by slot
      Varnode *vn = node.op->getIn(oldslot);
      if (!vn->isWritten()) {
	if (vn->isConstant())
	  vn->nzm = vn->getOffset();
	else {
	  vn->nzm = calc_mask(vn->getSize());
	  if (vn->isSpacebase())
	    vn->nzm &= ~((uintb)0xff); // Treat spacebase input as aligned
	}
      }
      else if (!vn->getDef()->isMark()) { // If haven't traversed before
	opstack.push_back(PcodeOpNode(vn->getDef(),0));
	vn->getDef()->setMark();
      }
    } while(!opstack.empty());
  }

  vector<PcodeOp *> worklist;
  // Clear marks and push ops with looping edges onto worklist
  for(oiter=beginOpAlive();oiter!=endOpAlive();++oiter) {
    PcodeOp *op = *oiter;
    op->clearMark();
    if (op->code() == CPUI_MULTIEQUAL)
      worklist.push_back(op);
  }

  // Continue to propagate changes along all edges
  while(!worklist.empty()) {
    PcodeOp *op = worklist.back();
    worklist.pop_back();
    Varnode *vn = op->getOut();
    if (vn == (Varnode *)0) continue;
    uintb nzmask = op->getNZMaskLocal(false);
    if (nzmask != vn->nzm) {
      vn->nzm = nzmask;
      for(oiter=vn->beginDescend();oiter!=vn->endDescend();++oiter)
	worklist.push_back(*oiter);
    }
  }
}

/// \brief Update Varnode properties based on (new) Symbol information
///
/// Boolean properties \b addrtied, \b addrforce, and \b nolocalalias
/// for Varnodes are updated based on new Symbol information they map to.
/// The caller can elect to update data-type information as well, where Varnodes
/// and their associated HighVariables have their data-type finalized based symbols.
/// \param lm is the Symbol scope within which to search for mapped Varnodes
/// \param updateDatatypes is \b true if the caller wants to update data-types
/// \param unmappedAliasCheck is \b true if an alias check should be performed on unmapped Varnodes
/// \return \b true if any Varnode was updated
bool Funcdata::syncVarnodesWithSymbols(const ScopeLocal *lm,bool updateDatatypes,bool unmappedAliasCheck)

{
  bool updateoccurred = false;
  VarnodeLocSet::const_iterator iter,enditer;
  Datatype *ct;
  SymbolEntry *entry;
  uint4 fl;

  iter = vbank.beginLoc(lm->getSpaceId());
  enditer = vbank.endLoc(lm->getSpaceId());
  while(iter != enditer) {
    Varnode *vnexemplar = *iter;
    entry = lm->findOverlap(vnexemplar->getAddr(),vnexemplar->getSize());
    ct = (Datatype *)0;
    if (entry != (SymbolEntry *)0) {
      fl = entry->getAllFlags();
      if (entry->getSize() >= vnexemplar->getSize()) {
	if (updateDatatypes) {
	  ct = entry->getSizedType(vnexemplar->getAddr(), vnexemplar->getSize());
	  if (ct != (Datatype *)0 && ct->getMetatype() == TYPE_UNKNOWN)
	    ct = (Datatype *)0;
	}
      }
      else { // Overlapping but not containing
	// This is usual indicative of a small locked symbol
	// getting put in a bigger register
	// Don't try to figure out type
	// Don't keep typelock and namelock
	fl &= ~((uint4)(Varnode::typelock|Varnode::namelock));
	// we do particularly want to keep the nolocalalias
      }
    }
    else { // Could not find any symbol
      if (lm->inScope(vnexemplar->getAddr(),vnexemplar->getSize(),
		      vnexemplar->getUsePoint(*this))) {
	// This is technically an error, there should be some
	// kind of symbol, if we are in scope
	fl = Varnode::mapped | Varnode::addrtied;
      }
      else if (unmappedAliasCheck) {
	// If the varnode is not in scope, check if we should treat as unaliased
	fl = lm->isUnmappedUnaliased(vnexemplar) ? Varnode::nolocalalias : 0;
      }
      else
	fl = 0;
    }
    if (syncVarnodesWithSymbol(iter,fl,ct))
	updateoccurred = true;
  }
  return updateoccurred;
}

/// A Varnode overlaps the given SymbolEntry.  Make sure the Varnode is part of the variable
/// underlying the Symbol.  If not, remap things so that the Varnode maps to a distinct Symbol.
/// In either case, attach the appropriate Symbol to the Varnode
/// \param entry is the given SymbolEntry
/// \param vn is the overlapping Varnode
/// \return the Symbol attached to the Varnode
Symbol *Funcdata::handleSymbolConflict(SymbolEntry *entry,Varnode *vn)

{
  if (vn->isInput() || vn->isAddrTied() ||
      vn->isPersist() || vn->isConstant() || entry->isDynamic()) {
    vn->setSymbolEntry(entry);
    return entry->getSymbol();
  }
  HighVariable *high = vn->getHigh();
  Varnode *otherVn;
  HighVariable *otherHigh = (HighVariable *)0;
  // Look for a conflicting HighVariable
  VarnodeLocSet::const_iterator iter = beginLoc(entry->getSize(),entry->getAddr());
  while(iter != endLoc()) {
    otherVn = *iter;
    if (otherVn->getSize() != entry->getSize()) break;
    if (otherVn->getAddr() != entry->getAddr()) break;
    HighVariable *tmpHigh = otherVn->getHigh();
    if (tmpHigh != high) {
      otherHigh = tmpHigh;
      break;
    }
    ++iter;
  }
  if (otherHigh == (HighVariable *)0) {
    vn->setSymbolEntry(entry);
    return entry->getSymbol();
  }

  // If we reach here, we have a conflicting variable
  buildDynamicSymbol(vn);
  return vn->getSymbolEntry()->getSymbol();
}

/// \brief Update properties (and the data-type) for a set of Varnodes associated with one Symbol
///
/// The set of Varnodes with the same size and address all have their boolean properties
/// updated to the given values. The set is specified by providing an iterator reference
/// to the first Varnode in the set assuming a 'loc' ordering. This iterator is updated
/// to point to the first Varnode after the affected set.
///
/// The only properties that can be effectively changed with this
/// routine are \b mapped, \b addrtied, \b addrforce, and \b nolocalalias.
/// HighVariable splits must occur if \b addrtied is cleared.
///
/// If the given data-type is non-null, an attempt is made to update all the Varnodes
/// to this data-type. The \b typelock and \b namelock properties cannot be changed here.
/// \param iter points to the first Varnode in the set
/// \param fl holds the new set of boolean properties
/// \param ct is the given data-type to set (or NULL)
/// \return \b true if at least one Varnode was modified
bool Funcdata::syncVarnodesWithSymbol(VarnodeLocSet::const_iterator &iter,uint4 fl,Datatype *ct)

{
  VarnodeLocSet::const_iterator enditer;
  Varnode *vn;
  uint4 vnflags;
  bool updateoccurred = false;
				// These are the flags we are going to try to update
  uint4 mask = Varnode::mapped;
				// We take special care with the addrtied flag
				// as we cannot set it here if it is clear
				// We can CLEAR but not SET the addrtied flag
				// If addrtied is cleared, so should addrforce
  if ((fl&Varnode::addrtied)==0) // Is the addrtied flags cleared
    mask |= Varnode::addrtied | Varnode::addrforce;
  // We can set the nolocalalias flag, but not clear it
  // If nolocalalias is set, then addrforce should be cleared
  if ((fl&Varnode::nolocalalias)!=0)
    mask |= Varnode::nolocalalias | Varnode::addrforce;
  fl &= mask;

  vn = *iter;
  enditer = vbank.endLoc(vn->getSize(),vn->getAddr());
  do {
    vn = *iter++;
    if (vn->isFree()) continue;
    vnflags = vn->getFlags();
    if (vn->mapentry != (SymbolEntry *)0) {		// If there is already an attached SymbolEntry (dynamic)
      uint4 localMask = mask & ~Varnode::mapped;	// Make sure 'mapped' bit is unchanged
      uint4 localFlags = fl & localMask;
      if ((vnflags & localMask) != localFlags) {
	updateoccurred = true;
	vn->setFlags(localFlags);
	vn->clearFlags((~localFlags)&localMask);
      }
    }
    else if ((vnflags & mask) != fl) { // We have a change
      updateoccurred = true;
      vn->setFlags(fl);
      vn->clearFlags((~fl)&mask);
    }
    if (ct != (Datatype *)0) {
      if (vn->updateType(ct,false,false))
	updateoccurred = true;
      vn->getHigh()->finalizeDatatype(ct);	// Permanently set the data-type on the HighVariable
    }
  } while(iter != enditer);
  return updateoccurred;
}

/// \brief Remap a Symbol to a given Varnode using a static mapping
///
/// Any previous links between the Symbol, the Varnode, and the associate HighVariable are
/// removed.  Then a new link is created.
/// \param vn is the given Varnode
/// \param sym is the Symbol the Varnode maps to
/// \param usepoint is the desired usepoint for the mapping
void Funcdata::remapVarnode(Varnode *vn,Symbol *sym,const Address &usepoint)

{
  vn->clearSymbolLinks();
  SymbolEntry *entry = localmap->remapSymbol(sym, vn->getAddr(), usepoint);
  vn->setSymbolEntry(entry);
}

/// \brief Remap a Symbol to a given Varnode using a new dynamic mapping
///
/// Any previous links between the Symbol, the Varnode, and the associate HighVariable are
/// removed.  Then a new dynamic link is created.
/// \param vn is the given Varnode
/// \param sym is the Symbol the Varnode maps to
/// \param usepoint is the code Address where the Varnode is defined
/// \param hash is the hash for the new dynamic mapping
void Funcdata::remapDynamicVarnode(Varnode *vn,Symbol *sym,const Address &usepoint,uint8 hash)

{
  vn->clearSymbolLinks();
  SymbolEntry *entry = localmap->remapSymbolDynamic(sym, hash, usepoint);
  vn->setSymbolEntry(entry);
}

/// PIECE operations put the given Varnode into a larger structure.  Find the resulting
/// whole Varnode, make sure it has a symbol assigned, and then assign the same symbol
/// to the given Varnode piece.  If the given Varnode has been merged with something
/// else or the whole Varnode can't be found, do nothing.
void Funcdata::linkProtoPartial(Varnode *vn)

{
  HighVariable *high = vn->getHigh();
  if (high->getSymbol() != (Symbol *)0) return;
  Varnode *rootVn = PieceNode::findRoot(vn);
  if (rootVn == vn) return;

  HighVariable *rootHigh = rootVn->getHigh();
  Varnode *nameRep = rootHigh->getNameRepresentative();
  Symbol *sym = linkSymbol(nameRep);
  if (sym == (Symbol *)0) return;
  rootHigh->establishGroupSymbolOffset();
  SymbolEntry *entry = sym->getFirstWholeMap();
  vn->setSymbolEntry(entry);
}

/// The Symbol is really attached to the Varnode's HighVariable (which must exist).
/// The only reason a Symbol doesn't get set is if, the HighVariable
/// is global and there is no pre-existing Symbol.  (see mapGlobals())
/// \param vn is the given Varnode
/// \return the associated Symbol or NULL
Symbol *Funcdata::linkSymbol(Varnode *vn)

{
  if (vn->isProtoPartial())
    linkProtoPartial(vn);
  HighVariable *high = vn->getHigh();
  SymbolEntry *entry;
  uint4 fl = 0;
  Symbol *sym = high->getSymbol();
  if (sym != (Symbol *)0) return sym; // Symbol already assigned

  Address usepoint = vn->getUsePoint(*this);
  // Find any entry overlapping base address
  entry = localmap->queryProperties(vn->getAddr(), 1, usepoint, fl);
  if (entry != (SymbolEntry *) 0) {
    sym = handleSymbolConflict(entry, vn);
  }
  else {			// Must create a symbol entry
    if (!vn->isPersist()) {	// Only create local symbol
      if (vn->isAddrTied())
	usepoint = Address();
      entry = localmap->addSymbol("", high->getType(), vn->getAddr(), usepoint);
      sym = entry->getSymbol();
      vn->setSymbolEntry(entry);
    }
  }

  return sym;
}

/// A reference to a symbol (i.e. &varname) is typically stored as a PTRSUB operation, where the
/// first input Varnode is a \e spacebase Varnode indicating whether the symbol is on the \e stack or at
/// a \e global RAM location.  The second input Varnode is a constant encoding the address of the symbol.
/// This method takes this constant Varnode, recovers the symbol it is referring to, and stores
/// on the HighVariable object attached to the Varnode.
/// \param vn is the constant Varnode (second input) to a PTRSUB operation
/// \return the symbol being referred to or null
Symbol *Funcdata::linkSymbolReference(Varnode *vn)

{
  PcodeOp *op = vn->loneDescend();
  Varnode *in0 = op->getIn(0);
  TypePointer *ptype = (TypePointer *)in0->getHigh()->getType();
  if (ptype->getMetatype() != TYPE_PTR) return (Symbol *)0;
  TypeSpacebase *sb = (TypeSpacebase *)ptype->getPtrTo();
  if (sb->getMetatype() != TYPE_SPACEBASE)
      return (Symbol *)0;
  Scope *scope = sb->getMap();
  Address addr = sb->getAddress(vn->getOffset(),in0->getSize(),op->getAddr());
  if (addr.isInvalid())
    throw LowlevelError("Unable to generate proper address from spacebase");
  SymbolEntry *entry = scope->queryContainer(addr,1,Address());
  if (entry == (SymbolEntry *)0)
    return (Symbol *)0;
  int4 off = (int4)(addr.getOffset() - entry->getAddr().getOffset()) + entry->getOffset();
  vn->setSymbolReference(entry, off);
  return entry->getSymbol();
}

/// Return the (first) Varnode that matches the given SymbolEntry
/// \param entry is the given SymbolEntry
/// \return a matching Varnode or null
Varnode *Funcdata::findLinkedVarnode(SymbolEntry *entry) const

{
  if (entry->isDynamic()) {
    DynamicHash dhash;
    Varnode *vn = dhash.findVarnode(this, entry->getFirstUseAddress(), entry->getHash());
    if (vn == (Varnode *)0 || vn->isAnnotation())
      return (Varnode *)0;
    return vn;
  }

  VarnodeLocSet::const_iterator iter,enditer;
  Address usestart = entry->getFirstUseAddress();
  enditer = vbank.endLoc(entry->getSize(),entry->getAddr());

  if (usestart.isInvalid()) {
    iter = vbank.beginLoc(entry->getSize(),entry->getAddr());
    if (iter == enditer)
      return (Varnode *)0;
    Varnode *vn = *iter;
    if (!vn->isAddrTied())
      return (Varnode *)0;	// Varnode(s) must be address tied in order to match this symbol
    return vn;
  }
  iter = vbank.beginLoc(entry->getSize(),entry->getAddr(),usestart,~((uintm)0));
  // TODO: Use a better end iterator
  for(;iter!=enditer;++iter) {
    Varnode *vn = *iter;
    Address usepoint = vn->getUsePoint(*this);
    if (entry->inUse(usepoint))
      return vn;
  }
  return (Varnode *)0;
}

/// Look for Varnodes that are (should be) mapped to the given SymbolEntry and
/// add them to the end of the result list.
/// \param entry is the given SymbolEntry to match
/// \param res is the container holding the result list of matching Varnodes
void Funcdata::findLinkedVarnodes(SymbolEntry *entry,vector<Varnode *> &res) const

{
  if (entry->isDynamic()) {
    DynamicHash dhash;
    Varnode *vn = dhash.findVarnode(this,entry->getFirstUseAddress(),entry->getHash());
    if (vn != (Varnode *)0)
      res.push_back(vn);
  }
  else {
    VarnodeLocSet::const_iterator iter = beginLoc(entry->getSize(),entry->getAddr());
    VarnodeLocSet::const_iterator enditer = endLoc(entry->getSize(),entry->getAddr());
    for(;iter!=enditer;++iter) {
      Varnode *vn = *iter;
      Address addr = vn->getUsePoint(*this);
      if (entry->inUse(addr)) {
	res.push_back(vn);
      }
    }
  }
}

/// If a Symbol is already attached, no change is made. Otherwise a special \e dynamic Symbol is
/// created that is associated with the Varnode via a hash of its local data-flow (rather
/// than its storage address).
/// \param vn is the given Varnode
void Funcdata::buildDynamicSymbol(Varnode *vn)

{
  if (vn->isTypeLock()||vn->isNameLock())
    throw RecovError("Trying to build dynamic symbol on locked varnode");
  if (!isHighOn())
    throw RecovError("Cannot create dynamic symbols until decompile has completed");
  HighVariable *high = vn->getHigh();
  if (high->getSymbol() != (Symbol *)0)
    return;			// Symbol already exists
  DynamicHash dhash;

  dhash.uniqueHash(vn,this);	// Calculate a unique dynamic hash for this varnode
  if (dhash.getHash() == 0)
    throw RecovError("Unable to find unique hash for varnode");

  Symbol *sym;
  if (vn->isConstant())
    sym = localmap->addEquateSymbol("",Symbol::force_hex, vn->getOffset(), dhash.getAddress(), dhash.getHash());
  else
    sym = localmap->addDynamicSymbol("",high->getType(),dhash.getAddress(),dhash.getHash());
  vn->setSymbolEntry(sym->getFirstWholeMap());
}

/// \brief Map properties of a dynamic symbol to a Varnode
///
/// Given a dynamic mapping, try to find the mapped Varnode, then adjust (type and flags)
/// to reflect this mapping.
/// \param entry is the (dynamic) Symbol entry
/// \param dhash is the dynamic mapping information
/// \return \b true if a Varnode was adjusted
bool Funcdata::attemptDynamicMapping(SymbolEntry *entry,DynamicHash &dhash)

{
  Symbol *sym = entry->getSymbol();
  if (sym->getScope() != localmap)
    throw LowlevelError("Cannot currently have a dynamic symbol outside the local scope");
  dhash.clear();
  int4 category = sym->getCategory();
  if (category == Symbol::union_facet) {
    return applyUnionFacet(entry, dhash);
  }
  Varnode *vn = dhash.findVarnode(this,entry->getFirstUseAddress(),entry->getHash());
  if (vn == (Varnode *)0) return false;
  if (vn->getSymbolEntry() != (SymbolEntry *)0) return false;	// Varnode is already labeled
  if (category == Symbol::equate) {	// Is this an equate symbol
    vn->setSymbolEntry(entry);
    return true;
  }
  else if (entry->getSize() == vn->getSize()) {
    if (vn->setSymbolProperties(entry))
      return true;
  }
  return false;
}

/// \brief Map the name of a dynamic symbol to a Varnode
///
/// Given a dynamic mapping, try to find the mapped Varnode, then attach the Symbol to the Varnode.
/// The name of the Symbol is used, but the data-type and possibly other properties are not
/// put on the Varnode.
/// \param entry is the (dynamic) Symbol entry
/// \param dhash is the dynamic mapping information
/// \return \b true if a Varnode was adjusted
bool Funcdata::attemptDynamicMappingLate(SymbolEntry *entry,DynamicHash &dhash)

{
  dhash.clear();
  Symbol *sym = entry->getSymbol();
  if (sym->getCategory() == Symbol::union_facet) {
    return applyUnionFacet(entry, dhash);
  }
  Varnode *vn = dhash.findVarnode(this,entry->getFirstUseAddress(),entry->getHash());
  if (vn == (Varnode *)0)
    return false;
  if (vn->getSymbolEntry() != (SymbolEntry *)0) return false; // Symbol already applied
  if (sym->getCategory() == Symbol::equate) {	// Equate symbol does not depend on size
    vn->setSymbolEntry(entry);
    return true;
  }
  if (vn->getSize() != entry->getSize()) {
    ostringstream s;
    s << "Unable to use symbol ";
    if (!sym->isNameUndefined())
	s << sym->getName() << ' ';
    s << ": Size does not match variable it labels";
    warningHeader(s.str());
    return false;
  }

  if (vn->isImplied()) {	// This should be finding an explicit, but a cast may have been inserted
    Varnode *newvn = (Varnode *)0;
    // Look at the "other side" of the cast
    if (vn->isWritten() && (vn->getDef()->code() == CPUI_CAST))
	newvn = vn->getDef()->getIn(0);
    else {
	PcodeOp *castop = vn->loneDescend();
	if ((castop != (PcodeOp *)0)&&(castop->code() == CPUI_CAST))
	  newvn = castop->getOut();
    }
    // See if the varnode on the other side is explicit
    if ((newvn != (Varnode *)0)&&(newvn->isExplicit()))
	vn = newvn;		// in which case we use it
  }

  vn->setSymbolEntry(entry);
  if (!sym->isTypeLocked()) {	// If the dynamic symbol did not lock its type
    localmap->retypeSymbol(sym,vn->getType()); // use the type propagated into the varnode
  }
  else if (sym->getType() != vn->getType()) {
    ostringstream s;
    s << "Unable to use type for symbol " << sym->getName();
    warningHeader(s.str());
    localmap->retypeSymbol(sym,vn->getType()); // use the type propagated into the varnode
  }
  return true;
}

/// \brief Replace all read references to the first Varnode with a second Varnode
///
/// \param vn is the first Varnode (being replaced)
/// \param newvn is the second Varnode (the replacement)
void Funcdata::totalReplace(Varnode *vn,Varnode *newvn)

{
  list<PcodeOp *>::const_iterator iter;
  PcodeOp *op;
  int4 i;

  iter = vn->beginDescend();
  while(iter != vn->endDescend()) {
    op = *iter++;	       // Increment before removing descendant
    i = op->getSlot(vn);
    opSetInput(op,newvn,i);
  }
}

/// \brief Replace every read reference of the given Varnode with a constant value
///
/// A new constant Varnode is created for each read site. If there are any marker ops
/// (MULTIEQUAL) a single COPY op is inserted and the marker input is set to be the
/// output of the COPY.
/// \param vn is the given Varnode
/// \param val is the constant value to replace it with
void Funcdata::totalReplaceConstant(Varnode *vn,uintb val)

{
  list<PcodeOp *>::const_iterator iter;
  PcodeOp *op;
  PcodeOp *copyop = (PcodeOp *)0;
  Varnode *newrep;
  int4 i;

  iter = vn->beginDescend();
  while(iter != vn->endDescend()) {
    op = *iter++;		// Increment before removing descendant
    i = op->getSlot(vn);
    if (op->isMarker()) {    // Do not put constant directly in marker
      if (copyop == (PcodeOp *)0) {
	if (vn->isWritten()) {
	  copyop = newOp(1,vn->getDef()->getAddr());
	  opSetOpcode(copyop,CPUI_COPY);
	  newrep = newUniqueOut(vn->getSize(),copyop);
	  opSetInput(copyop,newConstant(vn->getSize(),val),0);
	  opInsertAfter(copyop,vn->getDef());
	}
	else {
	  BlockBasic *bb = (BlockBasic *)getBasicBlocks().getBlock(0);
	  copyop = newOp(1,bb->getStart());
	  opSetOpcode(copyop,CPUI_COPY);
	  newrep = newUniqueOut(vn->getSize(),copyop);
	  opSetInput(copyop,newConstant(vn->getSize(),val),0);
	  opInsertBegin(copyop,bb);
	}
      }
      else
	newrep = copyop->getOut();
    }
    else
      newrep = newConstant(vn->getSize(),val);
    opSetInput(op,newrep,i);
  }
}

/// For the given Varnode, duplicate its defining PcodeOp at each read of the Varnode
/// so that the read becomes a new unique Varnode. This operation should not be performed on any
/// PcodeOp with side effects like CPUI_CALL.
/// \param vn is the given Varnode
void Funcdata::splitUses(Varnode *vn)

{
  PcodeOp *op = vn->getDef();
  Varnode *newvn;
  PcodeOp *newop,*useop;
  list<PcodeOp *>::iterator iter;
  int4 slot;

  iter = vn->descend.begin();
  if (iter == vn->descend.end()) return; // No descendants at all
  useop = *iter++;
  if (iter == vn->descend.end()) return; // Only one descendant
  for(;;) {
    slot = useop->getSlot(vn);		// Get first descendant
    newop = newOp(op->numInput(),op->getAddr());
    newvn = newVarnode(vn->getSize(),vn->getAddr(),vn->getType());
    opSetOutput(newop,newvn);
    opSetOpcode(newop,op->code());
    for(int4 i=0;i<op->numInput();++i)
      opSetInput(newop,op->getIn(i),i);
    opSetInput(useop,newvn,slot);
    opInsertBefore(newop,op);
    if (iter == vn->descend.end()) break;
    useop = *iter++;
  }
				// Dead-code actions should remove original op
}

/// Find the minimal Address range covering the given Varnode that doesn't split other Varnodes
/// \param vn is the given Varnode
/// \param sz is used to pass back the size of the resulting range
/// \return the starting address of the resulting range
Address Funcdata::findDisjointCover(Varnode *vn,int4 &sz)

{
  Address addr = vn->getAddr();
  Address endaddr = addr + vn->getSize();
  VarnodeLocSet::const_iterator iter = vn->lociter;

  while(iter != beginLoc()) {
    --iter;
    Varnode *curvn = *iter;
    Address curEnd = curvn->getAddr() + curvn->getSize();
    if (curEnd <= addr) break;
    addr = curvn->getAddr();
  }
  iter = vn->lociter;
  while(iter != endLoc()) {
    Varnode *curvn = *iter;
    ++iter;
    if (endaddr <= curvn->getAddr()) break;
    endaddr = curvn->getAddr() + curvn->getSize();
  }
  sz = (int4)(endaddr.getOffset() - addr.getOffset());
  return addr;
}

/// \brief Make sure every Varnode in the given list has a Symbol it will link to
///
/// This is used when Varnodes overlap a locked Symbol but extend beyond it.
/// An existing Symbol is passed in with a list of possibly overextending Varnodes.
/// The list is in Address order.  We check that each Varnode has a Symbol that
/// overlaps its first byte (to guarantee a link). If one doesn't exist it is created.
/// \param entry is the existing Symbol entry
/// \param list is the list of Varnodes
void Funcdata::coverVarnodes(SymbolEntry *entry,vector<Varnode *> &list)

{
  Scope *scope = entry->getSymbol()->getScope();
  for(int4 i=0;i<list.size();++i) {
    Varnode *vn = list[i];
    // We only need to check once for all Varnodes at the same Address
    // Of these, pick the biggest Varnode
    if (i+1<list.size() && list[i+1]->getAddr() == vn->getAddr())
      continue;
    Address usepoint = vn->getUsePoint(*this);
    SymbolEntry *overlapEntry = scope->findContainer(vn->getAddr(), vn->getSize(), usepoint);
    if (overlapEntry == (SymbolEntry *)0) {
      int4 diff = (int4)(vn->getOffset() - entry->getAddr().getOffset());
      ostringstream s;
      s << entry->getSymbol()->getName() << '_' << diff;
      if (vn->isAddrTied())
	usepoint = Address();
      scope->addSymbol(s.str(),vn->getHigh()->getType(),vn->getAddr(),usepoint);
    }
  }
}

/// \brief Cache information from a UnionFacetSymbol
///
/// The symbol forces a particular union field resolution for the associated PcodeOp and slot,
/// which are extracted from the given \e dynamic SymbolEntry.  The resolution is cached
/// in the \b unionMap so that it will get picked up by resolveInFlow() methods etc.
/// \param entry is the given SymbolEntry
/// \param dhash is preallocated storage for calculating the dynamic hash
/// \return \b true if the UnionFacetSymbol is successfully cached
bool Funcdata::applyUnionFacet(SymbolEntry *entry,DynamicHash &dhash)

{
  Symbol *sym = entry->getSymbol();
  PcodeOp *op = dhash.findOp(this, entry->getFirstUseAddress(), entry->getHash());
  if (op == (PcodeOp *)0)
    return false;
  int4 slot = DynamicHash::getSlotFromHash(entry->getHash());
  int4 fldNum = ((UnionFacetSymbol *)sym)->getFieldNumber();
  ResolvedUnion resolve(sym->getType(), fldNum, *glb->types);
  resolve.setLock(true);
  return setUnionField(sym->getType(),op,slot,resolve);
}

/// Search for \e addrtied Varnodes whose storage falls in the global Scope, then
/// build a new global Symbol if one didn't exist before.
void Funcdata::mapGlobals(void)

{
  SymbolEntry *entry;
  VarnodeLocSet::const_iterator iter,enditer;
  Varnode *vn,*maxvn;
  Datatype *ct;
  uint4 fl;
  vector<Varnode *> uncoveredVarnodes;
  bool inconsistentuse = false;

  iter = vbank.beginLoc(); // Go through all varnodes for this space
  enditer = vbank.endLoc();
  while(iter != enditer) {
    vn = *iter++;
    if (vn->isFree()) continue;
    if (!vn->isPersist()) continue; // Could be a code ref
    if (vn->getSymbolEntry() != (SymbolEntry *)0) continue;
    maxvn = vn;
    Address addr = vn->getAddr();
    Address endaddr = addr + vn->getSize();
    uncoveredVarnodes.clear();
    while(iter != enditer) {
      vn = *iter;
      if (!vn->isPersist()) break;
      if (vn->getAddr() < endaddr) {
	// Varnodes at the same base address will get linked to the Symbol at that address
	// even if the size doesn't match, but we check for internal Varnodes that
	// do not have an attached Symbol as these won't get linked to anything
	if (vn->getAddr() != addr && vn->getSymbolEntry() == (SymbolEntry *)0)
	  uncoveredVarnodes.push_back(vn);
	endaddr = vn->getAddr() + vn->getSize();
	if (vn->getSize() > maxvn->getSize())
	  maxvn = vn;
	++iter;
      }
      else
	break;
    }
    if ((maxvn->getAddr() == addr)&&(addr+maxvn->getSize() == endaddr))
      ct = maxvn->getHigh()->getType();
    else
      ct = glb->types->getBase(endaddr.getOffset()-addr.getOffset(),TYPE_UNKNOWN);

    fl = 0;
    // Assume existing symbol is addrtied, so use empty usepoint
    Address usepoint;
    // Find any entry overlapping base address
    entry = localmap->queryProperties(addr,1,usepoint,fl);
    if (entry==(SymbolEntry *)0) {
      Scope *discover = localmap->discoverScope(addr,ct->getSize(),usepoint);
      if (discover == (Scope *)0)
	throw LowlevelError("Could not discover scope");
      int4 index = 0;
      string symbolname = discover->buildVariableName(addr,usepoint,ct,index,
						      Varnode::addrtied|Varnode::persist);
      discover->addSymbol(symbolname,ct,addr,usepoint);
    }
    else if ((addr.getOffset()+ct->getSize())-1 > (entry->getAddr().getOffset()+entry->getSize()) -1) {
      inconsistentuse = true;
      if (!uncoveredVarnodes.empty())	// Provide Symbols for any uncovered internal Varnodes
	coverVarnodes(entry, uncoveredVarnodes);
    }
  }
  if (inconsistentuse)
    warningHeader("Globals starting with '_' overlap smaller symbols at the same address");
}

/// Make sure that if a Varnode exists representing the "this" pointer for the function, that it
/// is treated as pointer data-type.
void Funcdata::prepareThisPointer(void)

{
  int4 numInputs = funcp.numParams();
  for(int4 i=0;i<numInputs;++i) {
    ProtoParameter *param = funcp.getParam(i);
    if (param->isThisPointer() && param->isTypeLocked())
      return;		// Data-type will be obtained directly from symbol
  }

  // Its possible that a recommendation for the "this" pointer has already been been collected.
  // Currently the only type recommendations are for the "this" pointer. If there any, it is for "this"
  if (localmap->hasTypeRecommendations())
    return;

  Datatype *dt = glb->types->getTypeVoid();
  AddrSpace *spc = glb->getDefaultDataSpace();
  dt = glb->types->getTypePointer(spc->getAddrSize(),dt,spc->getWordSize());
  Address addr = funcp.getThisPointerStorage(dt);
  localmap->addTypeRecommendation(addr, dt);
}

/// \brief Test for legitimate double use of a parameter trial
///
/// The given trial is a \e putative input to first CALL, but can also trace its data-flow
/// into a second CALL. Return \b false if this leads us to conclude that the trial is not
/// a likely parameter.
/// \param opmatch is the first CALL linked to the trial
/// \param op is the second CALL
/// \param vn is the Varnode parameter for the second CALL
/// \param fl indicates what p-code ops were crossed to reach \e vn
/// \param trial is the given parameter trial
/// \return \b true for a legitimate double use
bool Funcdata::checkCallDoubleUse(const PcodeOp *opmatch,const PcodeOp *op,const Varnode *vn,uint4 fl,const ParamTrial &trial) const

{
  int4 j = op->getSlot(vn);
  if (j<=0) return false;	// Flow traces to indirect call variable, definitely not a param
  FuncCallSpecs	*fc = getCallSpecs(op);
  FuncCallSpecs *matchfc = getCallSpecs(opmatch);
  if (op->code() == opmatch->code()) {
    bool isdirect = (opmatch->code() == CPUI_CALL);
    if ((isdirect&&(matchfc->getEntryAddress() == fc->getEntryAddress())) ||
	((!isdirect)&&(op->getIn(0) == opmatch->getIn(0)))) { // If it is a call to the same function
      // Varnode addresses are unreliable for this test because copy propagation may have occurred
      // So we check the actual ParamTrial which holds the original address
//	  if (j == 0) return false;
      const ParamTrial &curtrial( fc->getActiveInput()->getTrialForInputVarnode(j) );
      if (curtrial.getAddress() == trial.getAddress()) { // Check for same memory location
	if (op->getParent() == opmatch->getParent()) {
	  if (opmatch->getSeqNum().getOrder() < op->getSeqNum().getOrder())
	    return true;	// opmatch has dibs, don't reject
	  // If use op occurs earlier than match op, we might still need to reject
	}
	else
	  return true;		// Same function, different basic blocks, assume legit doubleuse
      }
    }
  }

  if (fc->isInputActive()) {
    const ParamTrial &curtrial( fc->getActiveInput()->getTrialForInputVarnode(j) );
    if (curtrial.isChecked()) {
      if (curtrial.isActive())
	return false;
    }
    else if (TraverseNode::isAlternatePathValid(vn,fl))
      return false;
    return true;
  }
  return false;
}

/// \brief Test if the given Varnode seems to only be used by a CALL
///
/// Part of testing whether a Varnode makes sense as parameter passing storage is looking for
/// different explicit uses.
/// \param invn is the given Varnode
/// \param opmatch is the putative CALL op using the Varnode for parameter passing
/// \param trial is the parameter trial object associated with the Varnode
/// \param mainFlags are flags describing traversals along the \e main path, from \e invn to \e opmatch
/// \return \b true if the Varnode seems only to be used as parameter to \b opmatch
bool Funcdata::onlyOpUse(const Varnode *invn,const PcodeOp *opmatch,const ParamTrial &trial,uint4 mainFlags) const

{
  vector<TraverseNode> varlist;
  list<PcodeOp *>::const_iterator iter;
  const Varnode *vn,*subvn;
  const PcodeOp *op;
  int4 i;
  bool res = true;

  varlist.reserve(64);
  invn->setMark();		// Marks prevent infinite loops
  varlist.emplace_back(invn,mainFlags);

  for(i=0;i < varlist.size();++i) {
    vn = varlist[i].vn;
    uint4 baseFlags = varlist[i].flags;
    for(iter=vn->descend.begin();iter!=vn->descend.end();++iter) {
      op = *iter;
      if (op == opmatch) {
	if (op->getIn(trial.getSlot())==vn) continue;
      }
      uint4 curFlags = baseFlags;
      switch(op->code()) {
      case CPUI_BRANCH:		// These ops define a USE of a variable
      case CPUI_CBRANCH:
      case CPUI_BRANCHIND:
      case CPUI_LOAD:
      case CPUI_STORE:
	res = false;
	break;
      case CPUI_CALL:
      case CPUI_CALLIND:
	if (checkCallDoubleUse(opmatch,op,vn,curFlags,trial)) continue;
	res = false;
	break;
      case CPUI_INDIRECT:
	curFlags |= TraverseNode::indirectalt;
	break;
      case CPUI_COPY:
	if ((op->getOut()->getSpace()->getType()!=IPTR_INTERNAL)&&!op->isIncidentalCopy()&&!vn->isIncidentalCopy()) {
	  curFlags |= TraverseNode::actionalt;
	}
	break;
      case CPUI_RETURN:
	if (opmatch->code()==CPUI_RETURN) { // Are we in a different return
	  if (op->getIn(trial.getSlot())==vn) // But at the same slot
	    continue;
	}
	else if (activeoutput != (ParamActive *)0) {	// Are we in the middle of analyzing returns
	  if (op->getIn(0) != vn) {		// Unless we hold actual return value
	    if (!TraverseNode::isAlternatePathValid(vn,curFlags))
	      continue;				// Don't consider this a "use"
	  }
	}
	res = false;
	break;
      case CPUI_MULTIEQUAL:
      case CPUI_INT_SEXT:
      case CPUI_INT_ZEXT:
      case CPUI_CAST:
	break;
      case CPUI_PIECE:
	if (op->getIn(0) == vn) {	// Concatenated as most significant piece
	  if ((curFlags & TraverseNode::lsb_truncated) != 0) {
	    // Original lsb has been truncated and replaced
	    continue;	// No longer assume this is a possible use
	  }
	  curFlags |= TraverseNode::concat_high;
	}
	break;
      case CPUI_SUBPIECE:
	if (op->getIn(1)->getOffset() != 0) {			// Throwing away least significant byte(s)
	  if ((curFlags & TraverseNode::concat_high) == 0)	// If no previous concatenation has occurred
	    curFlags |= TraverseNode::lsb_truncated;		// Byte(s) of original value have been thrown away
	}
	break;
      default:
	curFlags |= TraverseNode::actionalt;
	break;
      }
      if (!res) break;
      subvn = op->getOut();
      if (subvn != (const Varnode *)0) {
	if (subvn->isPersist()) {
	  res = false;
	  break;
	}
	if (!subvn->isMark()) {
	  varlist.emplace_back(subvn,curFlags);
	  subvn->setMark();
	}
      }
    }
    if (!res) break;
  }
  for(i=0;i<varlist.size();++i)
    varlist[i].vn->clearMark();
  return res;
}

/// \brief Test if the given trial Varnode is likely only used for parameter passing
///
/// Flow is followed from the Varnode itself and from ancestors the Varnode was copied from
/// to see if it hits anything other than the given CALL or RETURN operation.
/// \param maxlevel is the maximum number of times to recurse through ancestor copies
/// \param invn is the given trial Varnode to test
/// \param op is the given CALL or RETURN
/// \param trial is the associated parameter trial object
/// \param offset is the offset within the current Varnode of the value ultimately copied into the trial
/// \param mainFlags describes traversals along the path from \e invn to \e op
/// \return \b true if the Varnode is only used for the CALL/RETURN
bool Funcdata::ancestorOpUse(int4 maxlevel,const Varnode *invn,
			     const PcodeOp *op,ParamTrial &trial,int4 offset,uint4 mainFlags) const

{
  if (maxlevel==0) return false;

  if (!invn->isWritten()) {
    if (!invn->isInput()) return false;
    if (!invn->isTypeLock()) return false;
				// If the input is typelocked
				// this is as good as being written
    return onlyOpUse(invn,op,trial,mainFlags); // Test if varnode is only used in op
  }

  const PcodeOp *def = invn->getDef();
  switch(def->code()) {
  case CPUI_INDIRECT:
    // An indirectCreation is an indication of an output trial, this should not count as
    // as an "only use"
    if (def->isIndirectCreation())
      return false;
    return ancestorOpUse(maxlevel-1,def->getIn(0),op,trial,offset,mainFlags | TraverseNode::indirect);
  case CPUI_MULTIEQUAL:
				// Check if there is any ancestor whose only
				// use is in this op
    if (def->isMark()) return false;	// Trim the loop
    def->setMark();		// Mark that this MULTIEQUAL is on the path
				// Note: onlyOpUse is using Varnode::setMark
    for(int4 i=0;i<def->numInput();++i) {
      if (ancestorOpUse(maxlevel-1,def->getIn(i),op,trial,offset,mainFlags)) {
	def->clearMark();
	return true;
      }
    }
    def->clearMark();
    return false;
  case CPUI_COPY:
    if ((invn->getSpace()->getType()==IPTR_INTERNAL)||def->isIncidentalCopy()||def->getIn(0)->isIncidentalCopy()) {
      return ancestorOpUse(maxlevel-1,def->getIn(0),op,trial,offset,mainFlags);
    }
    break;
  case CPUI_PIECE:
    // Concatenation tends to be artificial, so recurse through piece corresponding later SUBPIECE
    if (offset == 0)
      return ancestorOpUse(maxlevel-1,def->getIn(1),op,trial,0,mainFlags);	// Follow into least sig piece
    if (offset == def->getIn(1)->getSize())
      return ancestorOpUse(maxlevel-1,def->getIn(0),op,trial,0,mainFlags);	// Follow into most sig piece
    return false;
  case CPUI_SUBPIECE:
  {
    int4 newOff = def->getIn(1)->getOffset();
    // This is a rather kludgy way to get around where a DIV (or other similar) instruction
    // causes a register that looks like the high precision piece of the function return
    // to be set with the remainder as a side effect
    if (newOff==0) {
      const Varnode *vn = def->getIn(0);
      if (vn->isWritten()) {
	const PcodeOp *remop = vn->getDef();
	if ((remop->code()==CPUI_INT_REM)||(remop->code()==CPUI_INT_SREM))
	  trial.setRemFormed();
      }
    }
    if (invn->getSpace()->getType() == IPTR_INTERNAL || def->isIncidentalCopy() ||
	def->getIn(0)->isIncidentalCopy() ||
	invn->overlap(*def->getIn(0)) == newOff) {
      return ancestorOpUse(maxlevel-1,def->getIn(0),op,trial,offset + newOff,mainFlags);
    }
    break;
  }
  case CPUI_CALL:
  case CPUI_CALLIND:
    return false;		// A call is never a good indication of a single op use
  default:
    break;
  }
				// This varnode must be top ancestor at this point
  return onlyOpUse(invn,op,trial,mainFlags); // Test if varnode is only used in op
}

/// \return \b true if there are two input flows, one of which is a normal \e solid flow
bool AncestorRealistic::checkConditionalExe(State &state)

{
  const BlockBasic *bl = state.op->getParent();
  if (bl->sizeIn() != 2)
    return false;
  const FlowBlock *solidBlock = bl->getIn(state.getSolidSlot());
  if (solidBlock->sizeOut() != 1)
    return false;
//  const BlockBasic *callbl = stateStack[0].op->getParent();
//  if (callbl != bl) {
//    bool dominates = false;
//    FlowBlock *dombl = callbl->getImmedDom();
//    for(int4 i=0;i<2;++i) {
//      if (dombl == bl) {
//	dominates = true;
//	break;
//      }
//      if (dombl == (FlowBlock *)0) break;
//      dombl = dombl->getImmedDom();
//    }
//    if (!dominates)
//      return false;
//  }
  return true;
}

/// Analyze a new node that has just entered, during the depth-first traversal
/// \return the command indicating the next traversal step: push (enter_node), or pop (pop_success, pop_fail, pop_solid...)
int4 AncestorRealistic::enterNode(void)

{
  State &state(stateStack.back());
  // If the node has already been visited, we truncate the traversal to prevent cycles.
  // We always return success assuming the proper result will get returned along the first path
  Varnode *stateVn = state.op->getIn(state.slot);
  if (stateVn->isMark()) return pop_success;
  if (!stateVn->isWritten()) {
    if (stateVn->isInput()) {
      if (stateVn->isUnaffected()) return pop_fail;
      if (stateVn->isPersist()) return pop_success;	// A global input, not active movement, but a valid possibility
      if (!stateVn->isDirectWrite()) return pop_fail;
    }
    return pop_success;		// Probably a normal parameter, not active movement, but valid
  }
  mark(stateVn);		// Mark that the varnode has now been visited
  PcodeOp *op = stateVn->getDef();
  switch(op->code()) {
  case CPUI_INDIRECT:
    if (op->isIndirectCreation()) {	// Backtracking is stopped by a call
      trial->setIndCreateFormed();
      if (op->getIn(0)->isIndirectZero())	// True only if not a possible output
	return pop_failkill;		// Truncate this path, indicating killedbycall
      return pop_success;		// otherwise it could be valid
    }
    if (!op->isIndirectStore()) {	// If flow goes THROUGH a call
      if (op->getOut()->isReturnAddress()) return pop_fail;	// Storage address location is completely invalid
      if (trial->isKilledByCall()) return pop_fail;		// "Likely" killedbycall is invalid
    }
    stateStack.push_back(State(op,0));
    return enter_node;			// Enter the new node
  case CPUI_SUBPIECE:
    // Extracting to a temporary, or to the same storage location, or otherwise incidental
    // are viewed as just another node on the path to traverse
    if (op->getOut()->getSpace()->getType()==IPTR_INTERNAL
	|| op->isIncidentalCopy() || op->getIn(0)->isIncidentalCopy()
	|| (op->getOut()->overlap(*op->getIn(0)) == (int4)op->getIn(1)->getOffset())) {
      stateStack.push_back(State(op,state));
      return enter_node;		// Push into the new node
    }
    // For other SUBPIECES, do a minimal traversal to rule out unaffected or other invalid inputs,
    // but otherwise treat it as valid, active, movement into the parameter
    do {
      Varnode *vn = op->getIn(0);
      if ((!vn->isMark())&&(vn->isInput())) {
	if (vn->isUnaffected()||(!vn->isDirectWrite()))
	  return pop_fail;
      }
      op = vn->getDef();
    } while((op!=(PcodeOp *)0)&&((op->code() == CPUI_COPY)||(op->code()==CPUI_SUBPIECE)));
    return pop_solid;	// treat the COPY as a solid movement
  case CPUI_COPY:
  {
    // Copies to a temporary, or between varnodes with same storage location, or otherwise incidental
    // are viewed as just another node on the path to traverse
    if (op->getOut()->getSpace()->getType()==IPTR_INTERNAL
	|| op->isIncidentalCopy() || op->getIn(0)->isIncidentalCopy()
	|| (op->getOut()->getAddr() == op->getIn(0)->getAddr())) {
      stateStack.push_back(State(op,0));
      return enter_node;		// Push into the new node
    }
    // For other COPIES, do a minimal traversal to rule out unaffected or other invalid inputs,
    // but otherwise treat it as valid, active, movement into the parameter
    Varnode *vn = op->getIn(0);
    for(;;) {
      if ((!vn->isMark())&&(vn->isInput())) {
	if (!vn->isDirectWrite())
	  return pop_fail;
      }
      op = vn->getDef();
      if (op == (PcodeOp *)0) break;
      OpCode opc = op->code();
      if (opc == CPUI_COPY || opc == CPUI_SUBPIECE)
	vn = op->getIn(0);
      else if (opc == CPUI_PIECE)
	vn = op->getIn(1);		// Follow least significant piece
      else
	break;
    }
    return pop_solid;	// treat the COPY as a solid movement
  }
  case CPUI_MULTIEQUAL:
    multiDepth += 1;
    stateStack.push_back(State(op,0));
    return enter_node;				// Nothing to check, start traversing inputs of MULTIEQUAL
  case CPUI_PIECE:
    if (stateVn->getSize() > trial->getSize()) {	// Did we already pull-back from a SUBPIECE?
      // If the trial is getting pieced together and then truncated in a register,
      // this is evidence of artificial data-flow.
      if (state.offset == 0 && op->getIn(1)->getSize() <= trial->getSize()) {
	// Truncation corresponds to least significant piece, follow slot=1
        stateStack.push_back(State(op,1));
        return enter_node;
      }
      else if (state.offset == op->getIn(1)->getSize() && op->getIn(0)->getSize() <= trial->getSize()) {
	// Truncation corresponds to most significant piece, follow slot=0
        stateStack.push_back(State(op,0));
        return enter_node;
      }
      if (stateVn->getSpace()->getType() != IPTR_SPACEBASE) {
	return pop_fail;
      }
    }
    return pop_solid;
  default:
    return pop_solid;				// Any other LOAD or arithmetic/logical operation is viewed as solid movement
  }
}

/// Backtrack into a previously visited node
/// \param pop_command is the type of pop (pop_success, pop_fail, pop_failkill, pop_solid) being performed
/// \return the command to execute (push or pop) after the current pop
int4 AncestorRealistic::uponPop(int4 pop_command)

{
  State &state(stateStack.back());
  if (state.op->code() == CPUI_MULTIEQUAL) {	// All the interesting action happens for MULTIEQUAL branch points
    State &prevstate( stateStack[ stateStack.size()-2 ]);	// State previous the one being popped
    if (pop_command == pop_fail) {		// For a pop_fail, we always pop and pass along the fail
      multiDepth -= 1;
      stateStack.pop_back();
      return pop_command;
    }
    else if ((pop_command == pop_solid)&&(multiDepth == 1)&&(state.op->numInput()==2))
      prevstate.markSolid(state.slot);	// Indicate we have seen a "solid" that could override a "failkill"
    else if (pop_command == pop_failkill)
      prevstate.markKill();		// Indicate we have seen a "failkill" along at least one path of MULTIEQUAL
    state.slot += 1;				// Move to the next sibling
    if (state.slot == state.op->numInput()) {		// If we have traversed all siblings
      if (prevstate.seenSolid()) {			// If we have seen an overriding "solid" along at least one path
	pop_command = pop_success;			// this is always a success
	if (prevstate.seenKill()) {			// UNLESS we have seen a failkill
	  if (allowFailingPath) {
	    if (!checkConditionalExe(state))		// that can NOT be attributed to conditional execution
	      pop_command = pop_fail;			// in which case we fail despite having solid movement
	    else
	      trial->setCondExeEffect();			// Slate this trial for additional testing
	  }
	  else
	    pop_command = pop_fail;
	}
      }
      else if (prevstate.seenKill())	// If we have seen a failkill without solid movement
	pop_command = pop_failkill;			// this is always a failure
      else
	pop_command = pop_success;			// seeing neither solid nor failkill is still a success
      multiDepth -= 1;
      stateStack.pop_back();
      return pop_command;
    }
    return enter_node;
  }
  else {
    stateStack.pop_back();
    return pop_command;
  }
}

/// \brief Perform a full ancestor check on a given parameter trial
///
/// \param op is the CALL or RETURN to test parameter passing for
/// \param slot is the index of the particular input varnode to test
/// \param t is the ParamTrial object corresponding to the varnode
/// \param allowFail is \b true if we allow and test for failing paths due to conditional execution
/// \return \b true if the varnode has realistic ancestors for a parameter passing location
bool AncestorRealistic::execute(PcodeOp *op,int4 slot,ParamTrial *t,bool allowFail)

{
  trial = t;
  allowFailingPath = allowFail;
  markedVn.clear();		// Make sure to clear out any old data
  stateStack.clear();
  multiDepth = 0;
  // If the parameter itself is an input, we don't consider this realistic, we expect to see active
  // movement into the parameter. There are some cases where this doesn't happen, but they are rare and
  // failure here doesn't necessarily mean further analysis won't still declare this a parameter
  if (op->getIn(slot)->isInput()) {
    if (!trial->hasCondExeEffect())	// Make sure we are not retesting
      return false;
  }
  // Run the depth first traversal
  int4 command = enter_node;
  stateStack.push_back(State(op,slot));		// Start by entering the initial node
  while(!stateStack.empty()) {			// Continue until all paths have been exhausted
    switch(command) {
    case enter_node:
      command = enterNode();
      break;
    case pop_success:
    case pop_solid:
    case pop_fail:
    case pop_failkill:
      command = uponPop(command);
      break;
    }
  }
  for(int4 i=0;i<markedVn.size();++i)		// Clean up marks we left along the way
    markedVn[i]->clearMark();
  if (command == pop_success) {
    trial->setAncestorRealistic();
    return true;
  }
  else if (command == pop_solid) {
    trial->setAncestorRealistic();
    trial->setAncestorSolid();
    return true;
  }
  return false;
}

} // End namespace ghidra
