diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc index f21c0f823b3..25af29962eb 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc @@ -1053,6 +1053,93 @@ bool ActionConstantPtr::checkCopy(PcodeOp *op,Funcdata &data) return data.getArch()->infer_pointers; } +SymbolEntry *getSymbolEntry(Address &rampoint, bool &needexacthit, Funcdata &data) +{ + if (rampoint.isInvalid()) + return (SymbolEntry *)0; + // Since we are looking for a global address + // Assume it is address tied and use empty usepoint + SymbolEntry *entry = data.getScopeLocal()->getParent()->queryContainer(rampoint, 1, Address()); + if (entry != (SymbolEntry *)0) + { + Datatype *ptrType = entry->getSymbol()->getType(); + if (ptrType->getMetatype() == TYPE_ARRAY) + { + Datatype *ct = ((TypeArray *)ptrType)->getBase(); + // In the special case of strings (character arrays) we allow the constant pointer to + // refer to the middle of the string + if (ct->isCharPrint()) + needexacthit = false; + } + if (needexacthit && entry->getAddr() != rampoint) + return (SymbolEntry *)0; + } + + return entry; +} + +int8 isEntryMatch(SymbolEntry *entry, Address &rampoint, bool &isArray) { + int8 size = 0; + isArray = false; + if (entry != 0) + { + // If we found data at the specified address, use its size + size = entry->getSize(); + auto dt = entry->getSizedType(Address(rampoint.getSpace(), 0), size); + if (dt != 0 && dt->getMetatype() == TYPE_ARRAY) + { + int8 tmp; + isArray = true; + size = dt->getSubType(0, &tmp)->getSize(); + } + } + + return size; +} + +/// \brief Recursively search for additive constants and multiplicative constants +/// +/// Walking backward from the given Varnode, search for constants being added in and return +/// the sum of all the constants. Additionally pass back the biggest constant coefficient, for any term +/// formed with INT_MULT. +/// \param vn is the given root Varnode of the additive tree +/// \param multiplier will hold the biggest constant multiplier or 0, if no multiplier is present +/// \param maxLevel is the maximum depth to search in the tree +/// \return the sum of all constants in the additive expression +int8 ActionConstantPtr::getConstOffsetBack(Varnode *vn,int8 &multiplier,int4 maxLevel) + +{ + multiplier = 0; + int8 submultiplier; + if (vn->isConstant()) + return vn->getOffset(); + if (!vn->isWritten()) + return 0; + maxLevel -= 1; + if (maxLevel < 0) + return 0; + PcodeOp *op = vn->getDef(); + OpCode opc = op->code(); + int8 retval = 0; + if (opc == CPUI_INT_ADD) { + retval += getConstOffsetBack(op->getIn(0),submultiplier,maxLevel); + if (submultiplier > multiplier) + multiplier = submultiplier; + retval += getConstOffsetBack(op->getIn(1), submultiplier, maxLevel); + if (submultiplier > multiplier) + multiplier = submultiplier; + } + else if (opc == CPUI_INT_MULT) { + Varnode *cvn = op->getIn(1); + if (!cvn->isConstant()) return 0; + multiplier = cvn->getOffset(); + getConstOffsetBack(op->getIn(0), submultiplier, maxLevel); + if (submultiplier > 0) + multiplier *= submultiplier; // Only contribute to the multiplier + } + return retval; +} + /// \brief Determine if given Varnode might be a pointer constant. /// /// If it is a pointer, return the symbol it points to, or NULL otherwise. If it is determined @@ -1122,10 +1209,10 @@ SymbolEntry *ActionConstantPtr::isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op if (op->getIn(1-slot)->getTypeReadFacing(op)->getMetatype()==TYPE_PTR) return (SymbolEntry *)0; // If so, we are not a pointer // FIXME: need to fully explore additive tree - needexacthit = false; } else if (!glb->infer_pointers) return (SymbolEntry *)0; + needexacthit = false; break; case CPUI_STORE: if (slot != 2) @@ -1145,22 +1232,28 @@ SymbolEntry *ActionConstantPtr::isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op rampoint = glb->resolveConstant(spc,vn->getOffset(),vn->getSize(),op->getAddr(),fullEncoding); } - if (rampoint.isInvalid()) return (SymbolEntry *)0; - // Since we are looking for a global address - // Assume it is address tied and use empty usepoint - SymbolEntry *entry = data.getScopeLocal()->getParent()->queryContainer(rampoint,1,Address()); - if (entry != (SymbolEntry *)0) { - Datatype *ptrType = entry->getSymbol()->getType(); - if (ptrType->getMetatype() == TYPE_ARRAY) { - Datatype *ct = ((TypeArray *)ptrType)->getBase(); - // In the special case of strings (character arrays) we allow the constant pointer to - // refer to the middle of the string - if (ct->isCharPrint()) - needexacthit = false; + bool isArray = false; + SymbolEntry *entry = getSymbolEntry(rampoint, needexacthit, data); + int8 size = isEntryMatch(entry, rampoint, isArray); + + // Check if pointer is pointing at correctly size data + int8 mult; + getConstOffsetBack(op->getIn(0), mult, 8); + if (size == 1) { + // No multiply present for byte arrays + mult = 1; + } + + if (mult != size || !isArray) + { + // Check for 1-indexing + Address new_rampoint = rampoint + mult; + SymbolEntry *tmp_entry = getSymbolEntry(new_rampoint, needexacthit, data); + if (tmp_entry != 0 && mult == isEntryMatch(tmp_entry, new_rampoint, isArray) && isArray) { + entry = tmp_entry; } - if (needexacthit && entry->getAddr() != rampoint) - return (SymbolEntry *)0; } + return entry; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh index d484facb7ce..ded19524d9f 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh @@ -192,6 +192,7 @@ class ActionConstantPtr : public Action { static bool checkCopy(PcodeOp *op,Funcdata &data); static SymbolEntry *isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op,int4 slot, Address &rampoint,uintb &fullEncoding,Funcdata &data); + static int8 getConstOffsetBack(Varnode *vn,int8 &multiplier,int4 maxLevel); public: ActionConstantPtr(const string &g) : Action(0,"constantptr",g) {} ///< Constructor virtual void reset(Funcdata &data) { localcount = 0; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc index 491bd3815e4..ff1f3e214a9 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc @@ -418,6 +418,29 @@ void Funcdata::spacebaseConstant(PcodeOp *op,int4 slot,SymbolEntry *entry,const typelock = false; outvn->updateType(ptrentrytype,typelock,false); if (extra != 0) { + if ((intb)extra < 0) { + // Negative "extra" is likely an array offset + Datatype *dt = entry->getSizedType(Address(rampoint.getSpace(), 0), entry->getSize()); + if (dt != 0 && dt->getMetatype() == TYPE_ARRAY) + { + int8 tmp; + int8 datasize = dt->getSubType(0, &tmp)->getSize(); + extra += datasize; + + // Insert a negative add of Type's size + // and use the remainder (abs(type_size % extra) as the real extra + // This allows the negative value to be collapsed into a negative array offset later + PcodeOp *negOp = newOp(2,op->getAddr()); + opSetOpcode(negOp,CPUI_INT_ADD); + newUniqueOut(sz,negOp); + opInsertBefore(negOp,op); + Varnode *negconst = newConstant(sz, -datasize); + negconst->setPtrCheck(); + opSetInput(negOp,outvn,0); + opSetInput(negOp,negconst,1); + outvn = negOp->getOut(); + } + } if (extraOp == (PcodeOp *)0) { extraOp = newOp(2,op->getAddr()); opSetOpcode(extraOp,CPUI_INT_ADD);