Merge remote-tracking branch 'origin/GP-1683_FieldExtraction'

This commit is contained in:
Ryan Kurtz 2022-05-04 01:18:27 -04:00
commit de74f99231
3 changed files with 70 additions and 11 deletions

View file

@ -32,6 +32,7 @@ src/decompile/datatests/noforloop_alias.xml||GHIDRA||||END|
src/decompile/datatests/noforloop_globcall.xml||GHIDRA||||END|
src/decompile/datatests/noforloop_iterused.xml||GHIDRA||||END|
src/decompile/datatests/offsetarray.xml||GHIDRA||||END|
src/decompile/datatests/packstructaccess.xml||GHIDRA||||END|
src/decompile/datatests/pointercmp.xml||GHIDRA||||END|
src/decompile/datatests/pointerrel.xml||GHIDRA||||END|
src/decompile/datatests/pointersub.xml||GHIDRA||||END|

View file

@ -4736,7 +4736,7 @@ int4 RuleSubCancel::applyOp(PcodeOp *op,Funcdata &data)
}
/// \class RuleShiftSub
/// \brief Simplify SUBPIECE applied to INT_LEFT: `sub( V << 8*c, c) => sub(V,0)`
/// \brief Simplify SUBPIECE applied to INT_LEFT: `sub( V << 8*k, c) => sub(V,c-k)`
void RuleShiftSub::getOpList(vector<uint4> &oplist) const
{
@ -4749,13 +4749,20 @@ int4 RuleShiftSub::applyOp(PcodeOp *op,Funcdata &data)
if (!op->getIn(0)->isWritten()) return 0;
PcodeOp *shiftop = op->getIn(0)->getDef();
if (shiftop->code() != CPUI_INT_LEFT) return 0;
if (!shiftop->getIn(1)->isConstant()) return 0;
if (8*op->getIn(1)->getOffset() != shiftop->getIn(1)->getOffset())
return 0;
Varnode *sa = shiftop->getIn(1);
if (!sa->isConstant()) return 0;
int4 n = sa->getOffset();
if ((n & 7) != 0) return 0; // Must shift by a multiple of 8 bits
int4 c = op->getIn(1)->getOffset();
Varnode *vn = shiftop->getIn(0);
if (vn->isFree()) return 0;
int4 insize = vn->getSize();
int4 outsize = op->getOut()->getSize();
c -= n/8;
if (c < 0 || c + outsize > insize) // Check if this is a natural truncation
return 0;
data.opSetInput(op,vn,0);
data.opSetInput(op,data.newConstant(op->getIn(1)->getSize(),0),1);
data.opSetInput(op,data.newConstant(op->getIn(1)->getSize(),c),1);
return 1;
}
@ -6879,7 +6886,8 @@ int4 RuleExtensionPush::applyOp(PcodeOp *op,Funcdata &data)
/// \brief Pull-back SUBPIECE through INT_RIGHT and INT_SRIGHT
///
/// The form looks like:
/// - `sub( V>>c ,d ) => sub( V, d+k/8 ) >> (c-k) where k = (c/8)*8`
/// - `sub( V>>n ,c ) => sub( V, c+k/8 ) >> (n-k) where k = (n/8)*8` or
/// - `sub( V>>n, c ) => ext( sub( V, c+k/8 ) ) if n is big`
void RuleSubNormal::getOpList(vector<uint4> &oplist) const
{
@ -6901,13 +6909,35 @@ int4 RuleSubNormal::applyOp(PcodeOp *op,Funcdata &data)
int4 n = shiftop->getIn(1)->getOffset();
int4 c = op->getIn(1)->getOffset();
int4 k = (n/8);
int4 insize = a->getSize();
int4 outsize = op->getOut()->getSize();
// If totalcut + remain > original input, shrink cut
if (k+c+outsize > shiftout->getSize())
k = shiftout->getSize()-c-outsize;
// Total shift + outsize must be greater equal to size of input
if ((n+8*c+8*outsize < 8*a->getSize())&&(n != k*8)) return 0;
if ((n+8*c+8*outsize < 8*insize)&&(n != k*8)) return 0;
// If totalcut + remain > original input
if (k+c+outsize > insize) {
int4 truncSize = insize - c - k;
if (n == k*8 && truncSize > 0 && popcount(truncSize)==1) {
// We need an additional extension
c += k;
PcodeOp *newop = data.newOp(2,op->getAddr());
opc = (opc == CPUI_INT_SRIGHT) ? CPUI_INT_SEXT : CPUI_INT_ZEXT;
data.opSetOpcode(newop,CPUI_SUBPIECE);
data.newUniqueOut(truncSize,newop);
data.opSetInput(newop,a,0);
data.opSetInput(newop,data.newConstant(4,c),1);
data.opInsertBefore(newop,op);
data.opSetInput(op,newop->getOut(),0);
data.opRemoveInput(op,1);
data.opSetOpcode(op,opc);
return 1;
}
else
k = insize-c-outsize; // Or we can shrunk the cut
}
// if n == k*8, then a shift is unnecessary
c += k;
n -= k*8;
@ -6919,7 +6949,7 @@ int4 RuleSubNormal::applyOp(PcodeOp *op,Funcdata &data)
PcodeOp *newop = data.newOp(2,op->getAddr());
data.opSetOpcode(newop,CPUI_SUBPIECE);
data.newUniqueOut(op->getOut()->getSize(),newop);
data.newUniqueOut(outsize,newop);
data.opSetInput(newop,a,0);
data.opSetInput(newop,data.newConstant(4,c),1);
data.opInsertBefore(newop,op);

View file

@ -0,0 +1,28 @@
<decompilertest>
<binaryimage arch="x86:LE:64:default:gcc">
<!--
Access fields of a packed structure. Should see field accesses, not shifts and truncations.
Accesses are from beginning, middle, and end of the register holding the structure.
-->
<bytechunk space="ram" offset="0x100705" readonly="true">
e8d0ffffff4889c248c1e2
1048c1fa3001c248c1f83001d0c3
</bytechunk>
<symbol space="ram" offset="0x100705" name="access"/>
<symbol space="ram" offset="0x1006da" name="getstruct"/>
</binaryimage>
<script>
<com>option structalign 1</com>
<com>parse line struct tinystruct { int4 a; int2 b; int2 c; };</com>
<com>parse line extern tinystruct getstruct(int4 i);</com>
<com>parse line extern int4 access(int4 i);</com>
<com>lo fu access</com>
<com>dec</com>
<com>print C</com>
<com>quit</com>
</script>
<stringmatch name="Access packed fields #1" min="1" max="1">tVar1 = getstruct\(i\);</stringmatch>
<stringmatch name="Access packed fields #2" min="1" max="1">tVar1\.a</stringmatch>
<stringmatch name="Access packed fields #3" min="1" max="1">\(int4\)tVar1\.b</stringmatch>
<stringmatch name="Access packed fields #4" min="1" max="1">\(int4\)tVar1\.c</stringmatch>
</decompilertest>