Example #1
0
        private StridedInterval MakeInterval_IAdd(Expression left, Constant right)
        {
            if (right == null)
            {
                return(StridedInterval.Empty);
            }
            var cc = this.ccNext;

            if (this.invertCondition)
            {
                cc = cc.Invert();
            }
            switch (cc)
            {
            default:
                return(StridedInterval.Empty);

            case ConditionCode.UGE:
                long max = ~right.ToInt64();
                if (max < 0)
                {
                    return(StridedInterval.Empty);
                }
                return(StridedInterval.Create(1, 0, max));
            }
        }
Example #2
0
        private StridedInterval MakeInterval_ISub(Expression left, Constant right)
        {
            if (right == null)
            {
                return(StridedInterval.Empty);
            }
            var cc = this.ccNext;

            if (this.invertCondition)
            {
                cc = cc.Invert();
            }
            switch (cc)
            {
            case ConditionCode.ULE: return(StridedInterval.Create(1, 0, right.ToInt64()));

            case ConditionCode.ULT: return(StridedInterval.Create(1, 0, right.ToInt64() - 1));

            case ConditionCode.UGE: return(StridedInterval.Create(1, right.ToInt64(), long.MaxValue));

            case ConditionCode.UGT: return(StridedInterval.Create(1, right.ToInt64() + 1, long.MaxValue));

            case ConditionCode.EQ:
            case ConditionCode.NE:
            case ConditionCode.None:
                return(StridedInterval.Empty);

            default:
                throw new NotImplementedException($"Unimplemented condition code {cc}.");
            }
        }
Example #3
0
        public override ValueSet And(Constant right)
        {
            long v = right.ToInt64();

            return(new IntervalValueSet(
                       this.DataType,
                       StridedInterval.Create(1, 0, v)));
        }
Example #4
0
        public override ValueSet Shl(Constant cRight)
        {
            int v = (int)cRight.ToInt64();

            return(new IntervalValueSet(
                       this.DataType,
                       StridedInterval.Create(
                           SI.Stride << v,
                               SI.Low << v,
                               SI.High << v)));
        }
Example #5
0
        public override ValueSet IMul(Constant cRight)
        {
            long v = cRight.ToInt64();

            return(new IntervalValueSet(
                       this.DataType,
                       StridedInterval.Create(
                           SI.Stride * (int)v,
                           SI.Low * v,
                           SI.High * v)));
        }
Example #6
0
        public override ValueSet Sub(Constant right)
        {
            if (SI.Stride < 0)
            {
                return(new IntervalValueSet(
                           this.DataType,
                           StridedInterval.Empty));
            }
            long v = right.ToInt64();

            return(new IntervalValueSet(
                       this.DataType,
                       StridedInterval.Create(
                           SI.Stride,
                           SI.Low - v,
                           SI.High - v)));
        }
Example #7
0
        private SlicerResult FoundBoundaryCheck(BinaryExpression binExp, Expression liveKey)
        {
            var interval = binExp.Operator == Operator.ISub
                ? MakeInterval_ISub(liveKey, binExp.Right as Constant)
                : MakeInterval_IAdd(liveKey, binExp.Right as Constant);

            //$TODO: if jmptableindex and jmptableindextouse not same, inject a statement.
            this.JumpTableIndex         = liveKey;
            this.JumpTableIndexToUse    = binExp.Left;
            this.JumpTableIndexInterval = interval;
            DebugEx.Verbose(BackwardSlicer.trace, "  Found range of {0}: {1}", liveKey, JumpTableIndexInterval);
            return(new SlicerResult
            {
                SrcExpr = binExp,
                Stop = true
            });
        }
Example #8
0
        private StridedInterval MakeInterval_ISub(Expression left, Constant right)
        {
            if (right == null)
            {
                return(StridedInterval.Empty);
            }
            var cc = this.ccNext;

            if (this.invertCondition)
            {
                cc = cc.Invert();
            }
            switch (cc)
            {
            // NOTE: GE and GT should really be modeled with the semi-open range
            // [right,inf) and the open range (right,inf), respectively. See comment
            // for LE/LT.
            case ConditionCode.GE: return(StridedInterval.Create(1, right.ToInt64(), long.MaxValue));

            case ConditionCode.GT: return(StridedInterval.Create(1, right.ToInt64() + 1, long.MaxValue));

            // NOTE: LE and LT should really be modeled with the semi-open range
            // (inf,right] and the open range (inf,right). However, typically compilers
            // make the mistake and use LE/LT for boundary checking in indirect transfers.
            case ConditionCode.LE: return(StridedInterval.Create(1, 0, right.ToInt64()));

            case ConditionCode.LT: return(StridedInterval.Create(1, 0, right.ToInt64() - 1));

            case ConditionCode.ULE: return(StridedInterval.Create(1, 0, right.ToInt64()));

            case ConditionCode.ULT: return(StridedInterval.Create(1, 0, right.ToInt64() - 1));

            case ConditionCode.UGE: return(StridedInterval.Create(1, right.ToInt64(), long.MaxValue));

            case ConditionCode.UGT: return(StridedInterval.Create(1, right.ToInt64() + 1, long.MaxValue));

            case ConditionCode.EQ:
            case ConditionCode.NE:
            case ConditionCode.None:
                return(StridedInterval.Empty);

            default:
                throw new NotImplementedException($"Unimplemented condition code {cc}.");
            }
        }
Example #9
0
        private StridedInterval MakeInterval_And(Expression left, Constant right)
        {
            if (right == null)
            {
                return(StridedInterval.Empty);
            }
            long n = right.ToInt64();

            if (Bits.IsEvenPowerOfTwo(n + 1))
            {
                // n is a mask (0000...00111..111)
                return(StridedInterval.Create(1, 0, n));
            }
            else
            {
                return(StridedInterval.Empty);
            }
        }
Example #10
0
        /// <summary>
        /// Returns a valueset whose values are the truncation of this valueset's
        /// values.
        /// </summary>
        /// <param name="dt"></param>
        /// <returns></returns>
        public override ValueSet Truncate(DataType dt)
        {
            if (SI.Stride < 0)
            {
                return(this);
            }

            var             mask = (1 << dt.BitSize) - 1;
            StridedInterval siNew;

            if (SI.Low == SI.High)
            {
                siNew = StridedInterval.Constant(
                    Constant.Create(dt, SI.Low & mask));
            }
            else
            {
                siNew = StridedInterval.Create(
                    SI.Stride, 0, Math.Min(mask, SI.High));
            }
            return(new IntervalValueSet(dt, siNew));
        }
Example #11
0
 public IntervalValueSet(DataType dt, StridedInterval si) : base(dt)
 {
     this.SI = si;
 }
Example #12
0
        public ValueSet VisitBinaryExpression(BinaryExpression binExp)
        {
            var cLeft  = binExp.Left as Constant;
            var cRight = binExp.Right as Constant;

            //$TODO: it would be great if Address were simply a Constant.
            // but we have segmented addresses which need special treatment
            // everywhere.
            if (binExp.Left is Address aLeft)
            {
                cLeft = aLeft.ToConstant();
            }
            if (binExp.Right is Address aRight)
            {
                cRight = aRight.ToConstant();
            }

            if (cLeft != null && cRight != null)
            {
                return(new IntervalValueSet(
                           cLeft.DataType,
                           StridedInterval.Constant(
                               binExp.Operator.ApplyConstants(cLeft, cRight))));
            }

            if (cLeft == null && cRight != null)
            {
                var left = binExp.Left.Accept(this);
                if (binExp.Operator == Operator.IAdd)
                {
                    return(left.Add(cRight));
                }
                else if (binExp.Operator == Operator.And)
                {
                    return(left.And(cRight));
                }
                else if (binExp.Operator == Operator.Shl)
                {
                    return(left.Shl(cRight));
                }
                else if (binExp.Operator == Operator.IMul)
                {
                    return(left.IMul(cRight));
                }
                else if (binExp.Operator == Operator.ISub)
                {
                    return(left.Sub(cRight));
                }
            }
            if (cRight == null && cLeft != null)
            {
                var right = binExp.Right.Accept(this);
                if (binExp.Operator == Operator.IAdd)
                {
                    return(right.Add(cLeft));
                }
                else if (binExp.Operator == Operator.And)
                {
                    return(right.And(cLeft));
                }
            }
            if (binExp.Operator == Operator.IAdd)
            {
                if (cmp.Equals(binExp.Left, binExp.Right))
                {
                    var left = binExp.Left.Accept(this);
                    return(left.Shl(Constant.Int32(1)));
                }
            }
            return(IntervalValueSet.Any);
        }
Example #13
0
        public SlicerResult VisitBinaryExpression(BinaryExpression binExp, BackwardSlicerContext ctx)
        {
            if (binExp.Operator == Operator.Eq || binExp.Operator == Operator.Ne)
            {
                // Equality comparisons cannot contribute to determining the size
                // of the jump table; stop processing this instruction.
                return(null);
            }

            if ((binExp.Operator == Operator.Xor || binExp.Operator == Operator.ISub) &&
                this.slicer.AreEqual(binExp.Left, binExp.Right))
            {
                // XOR r,r (or SUB r,r) clears a register. Is it part of a live register?
                var regDst = this.assignLhs as Identifier;
                var regHi  = binExp.Left as Identifier;
                if (regHi != null && regDst != null &&
                    DomainOf(regDst) == regHi.Storage.Domain &&
                    regDst.Storage.OffsetOf(regHi.Storage) == 8)
                {
                    // The 8086 didn't have a MOVZX instruction, so clearing the high byte of a
                    // register BX was done by issuing XOR BH,BH
                    var seXor = new SlicerResult
                    {
                        SrcExpr   = new Cast(regDst.DataType, new Cast(PrimitiveType.Byte, this.assignLhs)),
                        LiveExprs = new Dictionary <Expression, BackwardSlicerContext>
                        {
                            {
                                this.assignLhs,
                                BackwardSlicerContext.Jump(new BitRange(0, 8))
                            }
                        }
                    };
                    return(seXor);
                }
            }

            var seLeft  = binExp.Left.Accept(this, ctx);
            var seRight = binExp.Right.Accept(this, ctx);

            if (seLeft == null && seRight == null)
            {
                return(null);
            }
            if (binExp.Operator == Operator.ISub && this.Live != null && (ctx.Type & ContextType.Condition) != 0)
            {
                var domLeft = DomainOf(seLeft.SrcExpr);

                if (Live.Count > 0)
                {
                    foreach (var live in Live)
                    {
                        if (live.Value.Type != ContextType.Jumptable)
                        {
                            continue;
                        }
                        if ((domLeft != StorageDomain.Memory && DomainOf(live.Key) == domLeft)
                            ||
                            (this.slicer.AreEqual(live.Key, binExp.Left)))
                        {
                            //$TODO: if jmptableindex and jmptableindextouse not same, inject a statement.
                            this.JumpTableIndex         = live.Key;
                            this.JumpTableIndexToUse    = binExp.Left;
                            this.JumpTableIndexInterval = MakeInterval_ISub(live.Key, binExp.Right as Constant);
                            DebugEx.Verbose(BackwardSlicer.trace, "  Found range of {0}: {1}", live, JumpTableIndexInterval);
                            return(new SlicerResult
                            {
                                SrcExpr = binExp,
                                Stop = true
                            });
                        }
                    }
                }
                else
                {
                    // We have no live variables, which means this subtraction instruction
                    // is both computing the jumptable index and also performing the
                    // comparison.
                    this.JumpTableIndex         = assignLhs;
                    this.JumpTableIndexToUse    = assignLhs;
                    this.JumpTableIndexInterval = MakeInterval_ISub(assignLhs, binExp.Right as Constant);
                    DebugEx.Verbose(BackwardSlicer.trace, "  Found range of {0}: {1}", assignLhs, JumpTableIndexInterval);
                    return(new SlicerResult
                    {
                        SrcExpr = null,     // the jump table expression already has the correct shape.
                        Stop = true
                    });
                }
            }
            else if (binExp.Operator == Operator.And)
            {
                this.JumpTableIndex         = binExp.Left;
                this.JumpTableIndexToUse    = binExp.Left;
                this.JumpTableIndexInterval = MakeInterval_And(binExp.Left, binExp.Right as Constant);
                return(new SlicerResult
                {
                    SrcExpr = binExp,
                    Stop = true,
                });
            }
            IEnumerable <KeyValuePair <Expression, BackwardSlicerContext> > liveExpr = seLeft.LiveExprs;

            if (seRight != null)
            {
                liveExpr = liveExpr.Concat(seRight.LiveExprs);
            }
            var se = new SlicerResult
            {
                LiveExprs = liveExpr
                            .GroupBy(e => e.Key)
                            .ToDictionary(k => k.Key, v => v.Max(vv => vv.Value)),
                SrcExpr = binExp,
            };

            return(se);
        }
Example #14
0
        public TableExtent DiscoverTableExtent(Address addrSwitch, RtlTransfer xfer, DecompilerEventListener listener)
        {
            if (!Start(rtlBlock, host.BlockInstructionCount(rtlBlock) - 1, xfer.Target))
            {
                // No registers were found, so we can't trace back.
                return(null);
            }
            while (Step())
            {
                ;
            }

            var jumpExpr = this.JumpTableFormat;
            var interval = this.JumpTableIndexInterval;
            var index    = this.JumpTableIndexToUse;
            var ctx      = new Dictionary <Expression, ValueSet>(new ExpressionValueComparer());

            if (index == null)
            {
                // Weren't able to find the index register,
                // try finding it by blind pattern matching.
                index = this.FindIndexWithPatternMatch(this.JumpTableFormat);
                if (index == null)
                {
                    // This is likely an indirect call like a C++
                    // vtable dispatch. Since these are common, we don't
                    // spam the user with warnings.
                    return(null);
                }

                // We have a jump table, and we've guessed the index expression.
                // At this point we've given up on knowing the exact size
                // of the table, but we do know that it must be at least
                // more than one entry. The safest assumption is that it
                // has two entries.
                listener.Warn(
                    listener.CreateAddressNavigator(host.Program, addrSwitch),
                    "Unable to determine size of call or jump table; there may be more than 2 entries.");
                ctx.Add(index, new IntervalValueSet(index.DataType, StridedInterval.Create(1, 0, 1)));
            }
            else if (interval.IsEmpty)
            {
                return(null);
            }
            else if (interval.High == Int64.MaxValue)
            {
                // We have no reasonable upper bound. We make the arbitrary
                // assumption that the jump table has 2 items; it wouldn't
                // make sense to be indexing otherwise.
                listener.Warn(
                    listener.CreateAddressNavigator(host.Program, addrSwitch),
                    "Unable to determine the upper bound of an indirect call or jump; there may be more than 2 entries.");
                var vs = new IntervalValueSet(
                    this.JumpTableIndex.DataType,
                    StridedInterval.Create(1, interval.Low, interval.Low + 1));
                ctx.Add(this.JumpTableIndexToUse, vs);
            }
            else
            {
                ctx.Add(this.JumpTableIndex, new IntervalValueSet(this.JumpTableIndex.DataType, interval));
            }
            var vse = new ValueSetEvaluator(host.Architecture, host.SegmentMap, ctx, this.processorState);

            var(values, accesses) = vse.Evaluate(jumpExpr);
            var vector = values.Values
                         .TakeWhile(c => c != Constant.Invalid)
                         .Take(2000)    // Arbitrary limit
                         .Select(ForceToAddress)
                         .TakeWhile(a => a != null)
                         .ToList();

            if (vector.Count == 0)
            {
                return(null);
            }
            return(new TableExtent
            {
                Targets = vector,
                Accesses = accesses,
                Index = index,
            });
        }
 private ValueSet IVS(int stride, long low, long high)
 {
     return(new IntervalValueSet(PrimitiveType.Word32, StridedInterval.Create(stride, low, high)));
 }
Example #16
0
        public SlicerResult VisitBinaryExpression(BinaryExpression binExp, BackwardSlicerContext ctx)
        {
            if (binExp.Operator == Operator.Eq || binExp.Operator == Operator.Ne)
            {
                // Equality comparisons cannot contribute to determining the size
                // of the jump table; stop processing this instruction.
                return(null);
            }

            if ((binExp.Operator == Operator.Xor || binExp.Operator == Operator.ISub) &&
                this.slicer.AreEqual(binExp.Left, binExp.Right))
            {
                // XOR r,r (or SUB r,r) clears a register. Is it part of a live register?
                var regDst = this.assignLhs as Identifier;
                var regHi  = binExp.Left as Identifier;
                if (regHi != null && regDst != null &&
                    DomainOf(regDst) == regHi.Storage.Domain &&
                    regDst.Storage.OffsetOf(regHi.Storage) == 8)
                {
                    // The 8086 didn't have a MOVZX instruction, so clearing the high byte of a
                    // register BX was done by issuing XOR BH,BH
                    var seXor = new SlicerResult
                    {
                        SrcExpr   = new Cast(regDst.DataType, new Cast(PrimitiveType.Byte, this.assignLhs)),
                        LiveExprs = new Dictionary <Expression, BackwardSlicerContext>
                        {
                            {
                                this.assignLhs,
                                BackwardSlicerContext.Jump(new BitRange(0, 8))
                            }
                        }
                    };
                    return(seXor);
                }
            }

            var seLeft  = binExp.Left.Accept(this, ctx);
            var seRight = binExp.Right.Accept(this, ctx);

            if (seLeft == null && seRight == null)
            {
                return(null);
            }
            if (binExp.Operator == Operator.ISub && Live != null)
            {
                var domLeft = DomainOf(seLeft.SrcExpr);
                foreach (var live in Live.Keys)
                {
                    if (DomainOf(live) == domLeft)
                    {
                        if (slicer.AreEqual(this.assignLhs, this.JumpTableIndex))
                        {
                            //$TODO: if jmptableindex and jmptableindextouse not same, inject a statement.
                            this.JumpTableIndex         = live;
                            this.JumpTableIndexToUse    = binExp.Left;
                            this.JumpTableIndexInterval = MakeInterval_ISub(live, binExp.Right as Constant);
                            DebugEx.PrintIf(BackwardSlicer.trace.TraceVerbose, "  Found range of {0}: {1}", live, JumpTableIndexInterval);
                            return(new SlicerResult
                            {
                                SrcExpr = binExp,
                                Stop = true
                            });
                        }
                    }
                    if (this.slicer.AreEqual(live, binExp.Left))
                    {
                        this.JumpTableIndex         = live;
                        this.JumpTableIndexToUse    = binExp.Left;
                        this.JumpTableIndexInterval = MakeInterval_ISub(live, binExp.Right as Constant);
                        return(new SlicerResult
                        {
                            SrcExpr = binExp,
                            Stop = true,
                        });
                    }
                }
            }
            else if (binExp.Operator == Operator.And)
            {
                this.JumpTableIndex         = binExp.Left;
                this.JumpTableIndexToUse    = binExp.Left;
                this.JumpTableIndexInterval = MakeInterval_And(binExp.Left, binExp.Right as Constant);
                return(new SlicerResult
                {
                    SrcExpr = binExp,
                    Stop = true,
                });
            }
            var se = new SlicerResult
            {
                LiveExprs = seLeft.LiveExprs.Concat(seRight.LiveExprs)
                            .GroupBy(e => e.Key)
                            .ToDictionary(k => k.Key, v => v.Max(vv => vv.Value)),
                SrcExpr = binExp,
            };

            return(se);
        }