mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-25 21:51:47 +00:00
Merge remote-tracking branch 'origin/GP-3842_PointerToArray'
(Closes #5591)
This commit is contained in:
commit
e47d57fb21
@ -53,6 +53,7 @@ src/decompile/datatests/pointercmp.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/pointerrel.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/pointersub.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/promotecompare.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/ptrtoarray.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/readvolatile.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/retstruct.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/sbyte.xml||GHIDRA||||END|
|
||||
|
@ -2325,34 +2325,43 @@ void ActionSetCasts::checkPointerIssues(PcodeOp *op,Varnode *vn,Funcdata &data)
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Test if the given cast conflict can be resolved by passing to the first structure field
|
||||
/// \brief Test if the given cast conflict can be resolved by passing to the first structure/array field
|
||||
///
|
||||
/// Test if the given Varnode data-type is a pointer to a structure and if interpreting
|
||||
/// Test if the current data-type is a pointer to a structure and if interpreting
|
||||
/// the data-type as a pointer to the structure's first field will get it to match the
|
||||
/// desired data-type.
|
||||
/// \param vn is the given Varnode
|
||||
/// \param op is the PcodeOp reading the Varnode
|
||||
/// \param ct is the desired data-type
|
||||
/// required data-type.
|
||||
/// \param reqtype is the required data-type
|
||||
/// \param curtype is the current data-type
|
||||
/// \param castStrategy is used to determine if the data-types are compatible
|
||||
/// \return \b true if a pointer to the first field makes sense
|
||||
bool ActionSetCasts::testStructOffset0(Varnode *vn,PcodeOp *op,Datatype *ct,CastStrategy *castStrategy)
|
||||
bool ActionSetCasts::testStructOffset0(Datatype *reqtype,Datatype *curtype,CastStrategy *castStrategy)
|
||||
|
||||
{
|
||||
if (ct->getMetatype() != TYPE_PTR) return false;
|
||||
Datatype *highType = vn->getHighTypeReadFacing(op);
|
||||
if (highType->getMetatype() != TYPE_PTR) return false;
|
||||
Datatype *highPtrTo = ((TypePointer *)highType)->getPtrTo();
|
||||
if (highPtrTo->getMetatype() != TYPE_STRUCT) return false;
|
||||
TypeStruct *highStruct = (TypeStruct *)highPtrTo;
|
||||
if (highStruct->numDepend() == 0) return false;
|
||||
vector<TypeField>::const_iterator iter = highStruct->beginField();
|
||||
if ((*iter).offset != 0) return false;
|
||||
Datatype *reqtype = ((TypePointer *)ct)->getPtrTo();
|
||||
Datatype *curtype = (*iter).type;
|
||||
if (reqtype->getMetatype() == TYPE_ARRAY)
|
||||
reqtype = ((TypeArray *)reqtype)->getBase();
|
||||
if (curtype->getMetatype() == TYPE_ARRAY)
|
||||
curtype = ((TypeArray *)curtype)->getBase();
|
||||
if (curtype->getMetatype() != TYPE_PTR) return false;
|
||||
Datatype *highPtrTo = ((TypePointer *)curtype)->getPtrTo();
|
||||
if (highPtrTo->getMetatype() == TYPE_STRUCT) {
|
||||
TypeStruct *highStruct = (TypeStruct *)highPtrTo;
|
||||
if (highStruct->numDepend() == 0) return false;
|
||||
vector<TypeField>::const_iterator iter = highStruct->beginField();
|
||||
if ((*iter).offset != 0) return false;
|
||||
reqtype = ((TypePointer *)reqtype)->getPtrTo();
|
||||
curtype = (*iter).type;
|
||||
if (reqtype->getMetatype() == TYPE_ARRAY)
|
||||
reqtype = ((TypeArray *)reqtype)->getBase();
|
||||
if (curtype->getMetatype() == TYPE_ARRAY)
|
||||
curtype = ((TypeArray *)curtype)->getBase();
|
||||
}
|
||||
else if (highPtrTo->getMetatype() == TYPE_ARRAY) {
|
||||
TypeArray *highArray = (TypeArray *)highPtrTo;
|
||||
reqtype = ((TypePointer *)reqtype)->getPtrTo();
|
||||
curtype = highArray->getBase();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
if (reqtype->getMetatype() == TYPE_VOID) {
|
||||
return false; // Don't induce PTRSUB for "void *"
|
||||
}
|
||||
return (castStrategy->castStandard(reqtype, curtype, true, true) == (Datatype *)0);
|
||||
}
|
||||
|
||||
@ -2519,22 +2528,31 @@ int4 ActionSetCasts::castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStr
|
||||
}
|
||||
}
|
||||
}
|
||||
OpCode opc = CPUI_CAST;
|
||||
if (!force) {
|
||||
outct = outHighResolve; // Type of result
|
||||
ct = castStrategy->castStandard(outct,tokenct,false,true);
|
||||
if (ct == (Datatype *)0) return 0;
|
||||
if (outct->getMetatype() == TYPE_PTR && testStructOffset0(outct, tokenct, castStrategy)) {
|
||||
opc = CPUI_PTRSUB;
|
||||
}
|
||||
else {
|
||||
ct = castStrategy->castStandard(outct,tokenct,false,true);
|
||||
if (ct == (Datatype *)0) return 0;
|
||||
}
|
||||
}
|
||||
// Generate the cast op
|
||||
vn = data.newUnique(outvn->getSize());
|
||||
vn->updateType(tokenct,false,false);
|
||||
vn->setImplied();
|
||||
newop = data.newOp(1,op->getAddr());
|
||||
newop = data.newOp((opc != CPUI_CAST) ? 2 : 1,op->getAddr());
|
||||
#ifdef CPUI_STATISTICS
|
||||
data.getArch()->stats->countCast();
|
||||
#endif
|
||||
data.opSetOpcode(newop,CPUI_CAST);
|
||||
data.opSetOpcode(newop,opc);
|
||||
data.opSetOutput(newop,outvn);
|
||||
data.opSetInput(newop,vn,0);
|
||||
if (opc != CPUI_CAST) {
|
||||
data.opSetInput(newop,data.newConstant(4, 0),1);
|
||||
}
|
||||
data.opSetOutput(op,vn);
|
||||
data.opInsertAfter(newop,op); // Cast comes AFTER this operation
|
||||
if (tokenct->needsResolution())
|
||||
@ -2612,7 +2630,7 @@ int4 ActionSetCasts::castInput(PcodeOp *op,int4 slot,Funcdata &data,CastStrategy
|
||||
if (vn->getType() == ct)
|
||||
return 1;
|
||||
}
|
||||
else if (testStructOffset0(vn, op, ct, castStrategy)) {
|
||||
else if (ct->getMetatype() == TYPE_PTR && testStructOffset0(ct, vn->getHighTypeReadFacing(op), castStrategy)) {
|
||||
// Insert a PTRSUB(vn,#0) instead of a CAST
|
||||
newop = insertPtrsubZero(op, slot, ct, data);
|
||||
if (vn->getHigh()->getType()->needsResolution())
|
||||
|
@ -319,7 +319,7 @@ public:
|
||||
/// immediately.
|
||||
class ActionSetCasts : public Action {
|
||||
static void checkPointerIssues(PcodeOp *op,Varnode *vn,Funcdata &data);
|
||||
static bool testStructOffset0(Varnode *vn,PcodeOp *op,Datatype *ct,CastStrategy *castStrategy);
|
||||
static bool testStructOffset0(Datatype *reqtype,Datatype *curtype,CastStrategy *castStrategy);
|
||||
static bool tryResolutionAdjustment(PcodeOp *op,int4 slot,Funcdata &data);
|
||||
static bool isOpIdentical(Datatype *ct1,Datatype *ct2);
|
||||
static int4 resolveUnion(PcodeOp *op,int4 slot,Funcdata &data);
|
||||
|
@ -368,6 +368,55 @@ bool PrintC::checkArrayDeref(const Varnode *vn) const
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Check that the output data-type is a pointer to an array and then that
|
||||
/// the second data-type is a pointer to the element type (of the array).
|
||||
/// If this holds and the input variable represents a symbol with an \e array data-type,
|
||||
/// return \b true.
|
||||
/// \return \b true if the CAST can be rendered as '&'
|
||||
bool PrintC::checkAddressOfCast(const PcodeOp *op) const
|
||||
|
||||
{
|
||||
Datatype *dt0 = op->getOut()->getHighTypeDefFacing();
|
||||
const Varnode *vnin = op->getIn(0);
|
||||
Datatype *dt1 = vnin->getHighTypeReadFacing(op);
|
||||
if (dt0->getMetatype() != TYPE_PTR || dt1->getMetatype() != TYPE_PTR)
|
||||
return false;
|
||||
const Datatype *base0 = ((const TypePointer *)dt0)->getPtrTo();
|
||||
const Datatype *base1 = ((const TypePointer *)dt1)->getPtrTo();
|
||||
if (base0->getMetatype() != TYPE_ARRAY)
|
||||
return false;
|
||||
int4 arraySize = base0->getSize();
|
||||
base0 = ((const TypeArray *)base0)->getBase();
|
||||
while(base0->getTypedef() != (Datatype *)0)
|
||||
base0 = base0->getTypedef();
|
||||
while(base1->getTypedef() != (Datatype *)0)
|
||||
base1 = base1->getTypedef();
|
||||
if (base0 != base1)
|
||||
return false;
|
||||
Datatype *symbolType = (Datatype *)0;
|
||||
if (vnin->getSymbolEntry() != (SymbolEntry *)0 && vnin->getHigh()->getSymbolOffset() == -1) {
|
||||
symbolType = vnin->getSymbolEntry()->getSymbol()->getType();
|
||||
}
|
||||
else if (vnin->isWritten()) {
|
||||
const PcodeOp *ptrsub = vnin->getDef();
|
||||
if (ptrsub->code() == CPUI_PTRSUB) {
|
||||
Datatype *rootType = ptrsub->getIn(0)->getHighTypeReadFacing(ptrsub);
|
||||
if (rootType->getMetatype() == TYPE_PTR) {
|
||||
rootType = ((TypePointer *)rootType)->getPtrTo();
|
||||
int8 off = ptrsub->getIn(1)->getOffset();
|
||||
symbolType = rootType->getSubType(off, &off);
|
||||
if (off != 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (symbolType == (Datatype *)0)
|
||||
return false;
|
||||
if (symbolType->getMetatype() != TYPE_ARRAY || symbolType->getSize() != arraySize)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// This is used for expression that require functional syntax, where the name of the
|
||||
/// function is the name of the operator. The inputs to the p-code op form the roots
|
||||
/// of the comma separated list of \e parameters within the syntax.
|
||||
@ -399,9 +448,17 @@ void PrintC::opFunc(const PcodeOp *op)
|
||||
void PrintC::opTypeCast(const PcodeOp *op)
|
||||
|
||||
{
|
||||
Datatype *dt = op->getOut()->getHighTypeDefFacing();
|
||||
if (dt->isPointerToArray()) {
|
||||
if (checkAddressOfCast(op)) {
|
||||
pushOp(&addressof,op);
|
||||
pushVn(op->getIn(0),op,mods);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!option_nocasts) {
|
||||
pushOp(&typecast,op);
|
||||
pushType(op->getOut()->getHighTypeDefFacing());
|
||||
pushType(dt);
|
||||
}
|
||||
pushVn(op->getIn(0),op,mods);
|
||||
}
|
||||
@ -798,13 +855,6 @@ void PrintC::opPtradd(const PcodeOp *op)
|
||||
{
|
||||
bool printval = isSet(print_load_value|print_store_value);
|
||||
uint4 m = mods & ~(print_load_value|print_store_value);
|
||||
if (!printval) {
|
||||
TypePointer *tp = (TypePointer *)op->getIn(0)->getHighTypeReadFacing(op);
|
||||
if (tp->getMetatype() == TYPE_PTR) {
|
||||
if (tp->getPtrTo()->getMetatype() == TYPE_ARRAY)
|
||||
printval = true;
|
||||
}
|
||||
}
|
||||
if (printval) // Use array notation if we need value
|
||||
pushOp(&subscript,op);
|
||||
else // just a '+'
|
||||
@ -820,8 +870,15 @@ static bool isValueFlexible(const Varnode *vn)
|
||||
{
|
||||
if ((vn->isImplied())&&(vn->isWritten())) {
|
||||
const PcodeOp *def = vn->getDef();
|
||||
if (def->code() == CPUI_PTRSUB) return true;
|
||||
if (def->code() == CPUI_PTRADD) return true;
|
||||
OpCode opc = def->code();
|
||||
if (opc == CPUI_COPY) {
|
||||
const Varnode *invn = def->getIn(0);
|
||||
if (!invn->isImplied() || !invn->isWritten())
|
||||
return false;
|
||||
opc = invn->getDef()->code();
|
||||
}
|
||||
if (opc == CPUI_PTRSUB) return true;
|
||||
if (opc == CPUI_PTRADD) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -1020,12 +1077,11 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
||||
// and this PTRSUB(*,0) represents changing
|
||||
// to treating it as a pointer to its element type
|
||||
if (!valueon) {
|
||||
if (flex) { // EMIT ( )
|
||||
// (*&struct->arrayfield)[i]
|
||||
// becomes struct->arrayfield[i]
|
||||
// Even though there is no valueon, the PTRSUB still acts as a dereference
|
||||
if (flex) { // EMIT ( )
|
||||
if (ptrel != (TypePointerRel *)0)
|
||||
pushTypePointerRel(op);
|
||||
pushVn(in0,op,m);
|
||||
pushVn(in0,op,m | print_load_value); // Absorb dereference into in0's defining op
|
||||
}
|
||||
else { // EMIT *( )
|
||||
pushOp(&dereference,op);
|
||||
@ -1035,11 +1091,12 @@ void PrintC::opPtrsub(const PcodeOp *op)
|
||||
}
|
||||
}
|
||||
else {
|
||||
// We need to show two dereferences here: one for the valueon and one for the PTRSUB
|
||||
if (flex) { // EMIT ( )[0]
|
||||
pushOp(&subscript,op);
|
||||
if (ptrel != (TypePointerRel *)0)
|
||||
pushTypePointerRel(op);
|
||||
pushVn(in0,op,m);
|
||||
pushVn(in0,op,m | print_load_value); // Absorb one dereference into in0's defining op
|
||||
push_integer(0,4,false,syntax,(Varnode *)0,op);
|
||||
}
|
||||
else { // EMIT (* )[0]
|
||||
|
@ -172,6 +172,7 @@ protected:
|
||||
virtual bool doEmitWideCharPrefix(void) const;
|
||||
|
||||
bool checkArrayDeref(const Varnode *vn) const; ///< Determine whether a LOAD/STORE expression requires pointer '*' syntax
|
||||
bool checkAddressOfCast(const PcodeOp *op) const; ///< Check if CAST can be printed as an '&'
|
||||
void emitStructDefinition(const TypeStruct *ct); ///< Emit the definition of a \e structure data-type
|
||||
void emitEnumDefinition(const TypeEnum *ct); ///< Emit the definition of an \e enumeration data-type
|
||||
void emitPrototypeOutput(const FuncProto *proto,const Funcdata *fd); ///< Emit the output data-type of a function prototype
|
||||
|
@ -899,6 +899,9 @@ void TypePointer::calcSubmeta(void)
|
||||
else if (ptrtoMeta == TYPE_UNION) {
|
||||
submeta = SUB_PTR_STRUCT;
|
||||
}
|
||||
else if (ptrtoMeta == TYPE_ARRAY) {
|
||||
flags |= pointer_to_array;
|
||||
}
|
||||
if (ptrto->needsResolution() && ptrtoMeta != TYPE_PTR)
|
||||
flags |= needs_resolution; // Inherit needs_resolution, but only if not a pointer
|
||||
}
|
||||
|
@ -156,7 +156,8 @@ protected:
|
||||
type_incomplete = 0x400, ///< Set if \b this (recursive) data-type has not been fully defined yet
|
||||
needs_resolution = 0x800, ///< Datatype (union, pointer to union) needs resolution before propagation
|
||||
force_format = 0x7000, ///< 3-bits encoding display format, 0=none, 1=hex, 2=dec, 3=oct, 4=bin, 5=char
|
||||
truncate_bigendian = 0x8000 ///< Pointer can be truncated and is big endian
|
||||
truncate_bigendian = 0x8000, ///< Pointer can be truncated and is big endian
|
||||
pointer_to_array = 0x10000 ///< Data-type is a pointer to an array
|
||||
};
|
||||
friend class TypeFactory;
|
||||
friend struct DatatypeCompare;
|
||||
@ -193,6 +194,7 @@ public:
|
||||
bool isVariableLength(void) const { return ((flags&variable_length)!=0); } ///< Is \b this a variable length structure
|
||||
bool hasSameVariableBase(const Datatype *ct) const; ///< Are these the same variable length data-type
|
||||
bool isOpaqueString(void) const { return ((flags&opaque_string)!=0); } ///< Is \b this an opaquely encoded string
|
||||
bool isPointerToArray(void) const { return ((flags&pointer_to_array)!=0); } ///< Is \b this a pointer to an array
|
||||
bool isPointerRel(void) const { return ((flags & is_ptrrel)!=0); } ///< Is \b this a TypePointerRel
|
||||
bool isFormalPointerRel(void) const { return (flags & (is_ptrrel | has_stripped))==is_ptrrel; } ///< Is \b this a non-ephemeral TypePointerRel
|
||||
bool hasStripped(void) const { return (flags & has_stripped)!=0; } ///< Return \b true if \b this has a stripped form
|
||||
|
@ -0,0 +1,61 @@
|
||||
<decompilertest>
|
||||
<!--
|
||||
Functions manipulating explicit pointer-to-array data-types.
|
||||
-->
|
||||
<binaryimage arch="x86:LE:64:default:gcc">
|
||||
<bytechunk space="ram" offset="0x10123e" readonly="true">
|
||||
f30f
|
||||
1efa554889e54883ec1048897df88975
|
||||
f4488b45f84883c0404889c7e846ffff
|
||||
ff488b45f84883e8804889c7e87dffff
|
||||
ff837df40a7508488145f80002000048
|
||||
8b45f84889c7e81cffffff488b45f848
|
||||
89c7e857ffffff488b45f8c9c3
|
||||
</bytechunk>
|
||||
<bytechunk space="ram" offset="0x10129d" readonly="true">
|
||||
f30f1e
|
||||
fa554889e54883ec70897d9c64488b04
|
||||
2528000000488945f831c0488d45b048
|
||||
8905522d0000488d45a44889c7e8b7fe
|
||||
ffff488d45a84883c0044889c7e8b6fe
|
||||
ffff488d3d372d0000e89bfeffff9048
|
||||
8b45f86448330425280000007405e86d
|
||||
fdffffc9c3
|
||||
</bytechunk>
|
||||
<symbol space="ram" offset="0x10123e" name="ptrToArray"/>
|
||||
<symbol space="ram" offset="0x10129d" name="passPtrToArray"/>
|
||||
</binaryimage>
|
||||
<script>
|
||||
<com>map addr r0x104018 int4 (*paiGlob)[16]</com>
|
||||
<com>map addr r0x104020 float4 globarray[1]</com>
|
||||
<com>map fun r0x101189 floatarray</com>
|
||||
<com>map fun r0x101198 intarray</com>
|
||||
<com>map fun r0x1011a7 display</com>
|
||||
<com>map fun r0x1011ee displayLow</com>
|
||||
<com>parse line extern void floatarray(float4 (*a)[1]);</com>
|
||||
<com>parse line extern void intarray(int4 (*a)[1]);</com>
|
||||
<com>parse line extern void display(int4 (*ptr)[16]);</com>
|
||||
<com>parse line extern void displayLow(int4 *ptr);</com>
|
||||
<com>parse line struct mystruct { int4 a; int4 b[1]; };</com>
|
||||
<com>lo fu ptrToArray</com>
|
||||
<com>dec</com>
|
||||
<com>print C</com>
|
||||
<com>lo fu passPtrToArray</com>
|
||||
<com>map addr s0xffffffffffffff9c float4 a[1]</com>
|
||||
<com>map addr s0xffffffffffffffa0 mystruct myval</com>
|
||||
<com>map addr s0xffffffffffffffa8 int4 c[16]</com>
|
||||
<com>dec</com>
|
||||
<com>print C</com>
|
||||
<com>quit</com>
|
||||
</script>
|
||||
<stringmatch name="Pointer to array #1" min="1" max="1">display\(param_1 \+ 1\);</stringmatch>
|
||||
<stringmatch name="Pointer to array #2" min="1" max="1">displayLow\(param_1\[2\]\);</stringmatch>
|
||||
<stringmatch name="Pointer to array #3" min="1" max="1">paiStack_10 = param_1 \+ 8;</stringmatch>
|
||||
<stringmatch name="Pointer to array #4" min="1" max="1">display\(paiStack_10\);</stringmatch>
|
||||
<stringmatch name="Pointer to array #5" min="1" max="1">displayLow\(\*paiStack_10\);</stringmatch>
|
||||
<stringmatch name="Pointer to array #6" min="1" max="1">return paiStack_10;</stringmatch>
|
||||
<stringmatch name="Pointer to array #7" min="1" max="1">paiGlob = &c;</stringmatch>
|
||||
<stringmatch name="Pointer to array #8" min="1" max="1">floatarray\(&a\);</stringmatch>
|
||||
<stringmatch name="Pointer to array #9" min="1" max="1">intarray\(&myval\.b\);</stringmatch>
|
||||
<stringmatch name="Pointer to array #10" min="1" max="1">floatarray\(&globarray\);</stringmatch>
|
||||
</decompilertest>
|
Loading…
Reference in New Issue
Block a user