Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 108 additions & 15 deletions Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a direct copy and paste from RulePtrsubUndo. I'm not versed enough with the codebase to know where the function should get moved to in order to be shared between the two, and didn't want to introduce a dependency from one to the other where it shouldn't be


{
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
Expand Down Expand Up @@ -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)
Expand All @@ -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;
}

Expand Down
1 change: 1 addition & 0 deletions Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.hh
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
23 changes: 23 additions & 0 deletions Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down