Ejemplo n.º 1
0
    def lookupAddress(self, fmt, address):
        """Find data of an appropriate format at a (possibly symbolic) address

            fmt can influence the results
                lookupAddress(single, address_of_v)  ->   v.x
                lookupAddress(Vector, address_of_v)  ->   v

            if fmt is unknown (or no match is found), ?????
        """
        base = None
        memOffset = 0
        others = []
        if isinstance(address, algebra.Literal):
            memOffset = address.value
        elif isinstance(address, algebra.Expression) and address.op == '+':
            memOffset = address.constant.value if address.constant else 0
            for term in address.args:
                if isinstance(term.type, basicTypes.Pointer):
                    if base:
                        raise Exception('adding pointers')
                    base = term
                else:
                    others.append(term)
        elif isinstance(address.type, basicTypes.Pointer):
            if basicTypes.isIndexable(address.type.pointedType):
                base = address
                memOffset = 0
            else:
                return algebra.Symbol(address.type.target if address.type.target else address.name,
                    address.type.pointedType)

        if not base:
            #check for trig lookup
            if fmt == basicTypes.single and memOffset in self.bindings['trigtables']:
                try:
                    angle = others[0].args[0].args[0]
                    return algebra.Symbol('{}Table({})'.format(self.bindings['trigtables'][memOffset], angle))
                except:
                    pass
            pair = self.relativeToGlobals(memOffset)
            if pair:
                base = algebra.Symbol('raw', basicTypes.Pointer(pair[0].type, pair[0].name))
                memOffset = pair[1]
            else:
                # no idea what we are looking at, process it anyway
                return buildExpr('@', fmt, address)

        if basicTypes.isIndexable(base.type.pointedType):
            if memOffset >= self.getSize(base.type.pointedType):
                raise Exception('trying to look up address {:#x} in {} (only {:#x} bytes)'.format(
                    memOffset, base.type.pointedType, self.getSize(base.type.pointedType)))
            if base.type.target:
                return self.subLookup(fmt, algebra.Symbol(base.type.target, base.type.pointedType), memOffset, others)
            else:
                return self.subLookup(fmt, base, memOffset, others)
        elif base.type.target and memOffset == 0 and not others:
            return algebra.Symbol(base.type.target, base.type.pointedType)
        else:
            return buildExpr('@', fmt, address)
Ejemplo n.º 2
0
    def subLookup(self, fmt, base, address, others=[]):
        """Recursively find data at the given address from the start of a type"""
        if isinstance(base.type, basicTypes.Array):
            spacing = self.getSize(base.type.pointedType)
            index = algebra.Literal(address // spacing)
            canIndex = True
            for o in others:
                if (isinstance(o, algebra.Expression) and o.op == '*'
                        and o.constant and o.constant.value == spacing):
                    index = buildExpr(
                        '+', index,
                        algebra.Expression.arithmeticMerge('*', o.args))
                else:
                    canIndex = False
                    break
            if canIndex:
                element = buildExpr('[', base, index)
                if basicTypes.isIndexable(base.type.pointedType):
                    return self.subLookup(fmt, element, address % spacing)
                else:
                    return element
            else:
                return buildExpr(
                    '@', fmt,
                    algebra.Expression.arithmeticMerge(
                        '+', [base, algebra.Literal(address)] + others))
        parentStruct = None
        if isinstance(base.type, basicTypes.Pointer):
            parentStruct = base.type.pointedType
        elif isinstance(base.type, str):
            parentStruct = base.type

        if parentStruct and parentStruct in self.bindings['structs']:
            members = self.bindings['structs'][parentStruct].members
            try:
                bestOffset = max(x for x in members if x <= address)
            except ValueError:  # nothing less
                pass
            else:
                newBase = buildExpr('.', base,
                                    algebra.Symbol(*members[bestOffset]))
                if address < bestOffset + self.getSize(newBase.type):
                    if basicTypes.isIndexable(newBase.type):
                        return self.subLookup(fmt, newBase,
                                              address - bestOffset, others)
                    if not others:
                        #TODO account for reading the lower short of a word, etc.
                        return newBase
        if others:
            return buildExpr(
                '@', fmt,
                algebra.arithmeticMerge(
                    '+', [base, algebra.Literal(address)] + others))
        else:
            return buildExpr(
                '.', base,
                algebra.Symbol(
                    '{}_{:#x}'.format(basicTypes.getCode(fmt), address), fmt))
Ejemplo n.º 3
0
 def arithmeticMerge(cls, op, args, flop=False):
     symbols = []
     newConstant = cls.opIdentities[op]
     for a in args:
         if isinstance(a, cls) and a.op == op:
             symbols.extend(a.args)
             if a.constant:
                 newConstant = cls.opLambdas[op](newConstant,
                                                 a.constant.value)
         elif isinstance(a, Literal):
             newConstant = cls.opLambdas[op](newConstant, a.value)
         else:
             symbols.append(a)
     newConstant = None if newConstant == cls.opIdentities[op] else Literal(
         newConstant)
     if symbols:  #in case I add symbolic cancellation later
         if len(symbols) == 1 and not newConstant:
             return symbols[0]
         else:
             #multiple expressions summed
             if flop:
                 newType = basicTypes.single
             else:
                 newType = basicTypes.word
                 for s in symbols:
                     if basicTypes.isIndexable(s.type):
                         newType = basicTypes.address
                         break
             return cls(op, symbols, constant=newConstant, fmt=newType)
     elif newConstant:
         return newConstant
     else:
         return Literal(cls.opIdentities[op])
Ejemplo n.º 4
0
    def build(cls, op, left, right, flop=False):

        if op == 'NOR':  #why is this a thing
            return cls('~', [cls.build('|', left, right, flop)])

        if op == '[':
            return cls('[', [left], fmt=left.type.pointedType, constant=right)

        if isinstance(left, Literal):
            if isinstance(right, Literal):
                #two literals, completely reducible
                return Literal(cls.opLambdas[op](left.value, right.value))
            left, right = right, left
        #left is not a literal, right may be

        if op == '*' and left == right:
            return cls('**', [left],
                       constant=Literal(2),
                       fmt=basicTypes.single if flop else basicTypes.word)

        if op in ['==', '!='] and isinstance(right, Literal):
            if left.type == basicTypes.boolean and right == 0:
                return left if op == '!=' else left.negated()
            if basicTypes.isIndexable(left.type) and right == 0:
                return left
            if isinstance(left.type, basicTypes.EnumType):
                right.type = left.type

        # simplify multiplications by constants
        if op == '<<' and isinstance(
                right,
                Literal) and right.value < 8:  #assume real shifts are by more
            op, right = '*', Literal(2**right.value)
        elif op in '+-' and isinstance(left, cls) and left.op == '*':
            if isinstance(left, cls) and len(
                    left.args) == 1 and left.args[0] == right:
                return cls('*', [right], left.type,
                           Literal(cls.opLambdas[op](left.constant.value, 1)))

        if op in '+*|':
            return cls.arithmeticMerge(op, [left, right], flop)
        else:
            new = cls(op, [left, right])

        if op in '< > <= >= == !='.split():
            new.type = basicTypes.boolean

        if op == '.':
            new.type = right.type

        return new
Ejemplo n.º 5
0
    def read(self, var, fmt=basicTypes.unknown):
        """Retrive (an appropriate representation of) the value in a register and track its usage

            var should be a register or Stack() object

            Depending on the expected format, the stored value may be altered substantially

        """
        if var == Register.R0:  #zero is zero, shouldn't remember type info
            return algebra.Literal(0)
        if var in self.states:
            uncertain = False
            for st in reversed(self.states[var]):
                if self.now.implies(
                        st.context)[0]:  # this state definitely occurred
                    if uncertain:
                        st.explicit = True
                        break
                    else:
                        if isinstance(st.value, algebra.Literal):
                            if isinstance(fmt, basicTypes.EnumType):
                                st.value = self.getEnumValue(
                                    fmt, st.value.value)
                        elif basicTypes.isIndexable(fmt):
                            st.value = self.lookupAddress(fmt, st.value)
                        elif st.value.type in [
                                basicTypes.unknown, basicTypes.bad
                        ]:
                            st.value.type = fmt
                        return st.value
                elif self.now.isCompatibleWith(st.context):
                    st.explicit = True
                    uncertain = True
            return algebra.Symbol(VariableHistory.getName(var), fmt)
        else:
            symName = VariableHistory.getName(var)
            if VariableHistory.couldBeArg(var):
                self.argList.append(var)
                symName = 'arg_' + symName
            self.states[var].append(
                VariableState(self.getName(var), algebra.Symbol(symName, fmt),
                              self.now))
            return self.states[var][-1].value