Source code for microprobe.code.address

# Copyright 2011-2021 IBM Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
""":mod:`microprobe.code.address` module

"""

# Futures
from __future__ import absolute_import, annotations, print_function

# Built in modules
import hashlib
from typing import TYPE_CHECKING, Union

# Third party modules


# Own modules
from microprobe.code.var import Variable
from microprobe.exceptions import MicroprobeCodeGenerationError
from microprobe.utils.logger import get_logger
from microprobe.utils.typeguard_decorator import typeguard_testsuite

# Type hinting
if TYPE_CHECKING:
    from microprobe.code.ins import Instruction

# Constants
LOG = get_logger(__name__)
__all__ = ["MemoryValue", "Address", "InstructionAddress"]

# Functions


# Classes
[docs] @typeguard_testsuite class Address: """Class to represent an address.""" _cmp_attributes = ["_base_address", "_displacement"]
[docs] def __init__(self, base_address: Variable | str | None = None, displacement: int = 0): """ :param base_address: (Default value = None) :param displacement: (Default value = 0) """ assert isinstance(displacement, int) self._base_address = base_address self._displacement = displacement if isinstance(base_address, self.__class__): self._displacement += base_address.displacement self._base_address = base_address.base_address if self._base_address is not None: assert isinstance(self._base_address, tuple([str] + [Variable])) self._hash = None
@property def base_address(self) -> Union[Variable, str, None]: """Base address of the address (:class:`~.str`)""" return self._base_address @property def displacement(self): """Displacement of the address (:class:`~.int`)""" return self._displacement
[docs] def check_alignment(self, align: int): """Check if the address is aligned to align""" return self._displacement % align == 0
[docs] def copy(self): """Returns a copy of the address.""" return self.__class__(base_address=self.base_address, displacement=self.displacement)
def __add__(self, other: Address | int): """ :param other: """ if isinstance(other, self.__class__): if self.base_address != other.base_address: raise MicroprobeCodeGenerationError("I can not add '%s' " "and '%s'" % (self, other)) return self.__class__(self.base_address, self.displacement + other.displacement) elif isinstance(other, int): return self.__class__(self.base_address, self.displacement + other) else: raise NotImplementedError def _check_cmp(self, other: Address): if not isinstance(other, self.__class__): raise NotImplementedError("%s != %s" % (other.__class__, self.__class__)) def __eq__(self, other: object): """x.__eq__(y) <==> x==y""" if not isinstance(other, self.__class__): return False for attr in self._cmp_attributes: if not getattr(self, attr) == getattr(other, attr): return False return True def __ne__(self, other: object): """x.__ne__(y) <==> x!=y""" if not isinstance(other, self.__class__): return False for attr in self._cmp_attributes: if not getattr(self, attr) == getattr(other, attr): return True return False def __lt__(self, other: object): """x.__lt__(y) <==> x<y""" if not isinstance(other, self.__class__): return False for attr in self._cmp_attributes: if getattr(self, attr) < getattr(other, attr): return True elif getattr(self, attr) > getattr(other, attr): return False return False def __gt__(self, other: object): """x.__gt__(y) <==> x>y""" if not isinstance(other, self.__class__): return False for attr in self._cmp_attributes: if getattr(self, attr) > getattr(other, attr): return True elif getattr(self, attr) < getattr(other, attr): return False return False def __le__(self, other: object): """x.__le__(y) <==> x<=y""" if not isinstance(other, self.__class__): return False for attr in self._cmp_attributes: if getattr(self, attr) <= getattr(other, attr): continue else: return False return True def __ge__(self, other: object): """x.__ge__(y) <==> x>=y""" if not isinstance(other, self.__class__): return False for attr in self._cmp_attributes: if getattr(self, attr) >= getattr(other, attr): continue else: return False return True def __hash__(self): """ """ if self._hash is None: self._hash = int( hashlib.sha512(str(self).encode()).hexdigest(), 16) return self._hash def __iadd__(self, other: object): """ :param other: """ if isinstance(other, self.__class__): if self.base_address != other.base_address: raise MicroprobeCodeGenerationError("I can not add '%s'" " and '%s'" % (self, other)) return self.__class__(self.base_address, self.displacement + other.displacement) elif isinstance(other, int): return self.__class__(self.base_address, self.displacement + other) else: raise NotImplementedError def __mod__(self, other: object): """ :param other: """ if isinstance(other, self.__class__): if self.base_address != other.base_address: raise MicroprobeCodeGenerationError("I can not compute the " "module '%s' and '%s'" % (self, other)) return self.__class__(self.base_address, self.displacement + other.displacement) elif isinstance(other, int): if isinstance(self._base_address, int): return (self._base_address + self.displacement) % other return self.displacement % other else: raise NotImplementedError def __radd__(self, other: object): """ :param other: """ if isinstance(other, self.__class__): if self.base_address != other.base_address: raise MicroprobeCodeGenerationError("I can not add '%s' and " "'%s'" % (self, other)) return self.__class__(self.base_address, self.displacement + other.displacement) elif isinstance(other, int): return self.__class__(self.base_address, self.displacement + other) else: raise NotImplementedError def __repr__(self): """ """ return "%s(%s+0x%016x)" % (self.__class__.__name__, self.base_address, self.displacement) def __rsub__(self, other: object): """ :param other: """ if isinstance(other, (Address, InstructionAddress)): if self.base_address != other.base_address: raise MicroprobeCodeGenerationError("I can not sub '%s' " "and '%s'" % (self, other)) return other.displacement - self.displacement elif isinstance(other, int): return self.__class__(self.base_address, self.displacement - other) else: raise NotImplementedError( "Substraction not implemented for %s and %s " "objects" % (self.__class__, other.__class__)) def __str__(self): """ """ return "%s(%s+0x%016x)" % (self.__class__.__name__, self.base_address, self.displacement) def __sub__(self, other: object): """ :param other: """ if isinstance(other, self.__class__): if self.base_address != other.base_address: raise MicroprobeCodeGenerationError("I can not sub '%s' " "and '%s'" % (self, other)) return self.displacement - other.displacement elif isinstance(other, int): return self.__class__(self.base_address, self.displacement - other) else: LOG.critical("%s != %s", self, other) LOG.critical("%s != %s", type(self), type(other)) raise NotImplementedError
[docs] @typeguard_testsuite class InstructionAddress(Address): """Class to represent an instruction address."""
[docs] def __init__(self, base_address: Variable | str | None = None, displacement: int = 0, instruction: Instruction | None = None): """ :param base_address: (Default value = None) :param displacement: (Default value = 0) :param instruction: (Default value = None) """ super(InstructionAddress, self).__init__(base_address=base_address, displacement=displacement) self._instruction = instruction
@property def target_instruction(self): """Target instruction (:class:`~.Instruction`)""" return self._instruction
[docs] def set_target_instruction(self, instruction: Instruction): """Sets the instruction to which this address is pointing. :param instruction: Target instruction :type instruction: :class:`~.Instruction` """ self._instruction = instruction
def __add__(self, other: Address | int): """ :param other: """ self._instruction = None return super(InstructionAddress, self).__add__(other) def __iadd__(self, other: object): """ :param other: """ self._instruction = None return super(InstructionAddress, self).__iadd__(other) def __mod__(self, other: object): """ :param other: """ self._instruction = None return super(InstructionAddress, self).__mod__(other) def __radd__(self, other: object): """ :param other: """ self._instruction = None return super(InstructionAddress, self).__radd__(other) def __rsub__(self, other: object): """ :param other: """ self._instruction = None return super(InstructionAddress, self).__rsub__(other) def __sub__(self, other: object): """ :param other: """ self._instruction = None return super(InstructionAddress, self).__sub__(other)
[docs] @typeguard_testsuite class MemoryValue(object): """Class to represent a value in memory.""" _cmp_attributes = ['address', 'value', 'length']
[docs] def __init__(self, address: Address, value: int | float, length: int): """ :param address: :param value: :param length: """ self._address = address self._value = value self._length = length
@property def address(self): """Address of the memory value Address of the memory value (:class:`~.Address`) """ return self._address @property def length(self): """Length of the memory value (:class:`~.int`)""" return self._length @property def value(self): """Actual memory value (:class:`~.int`)""" return self._value def _check_cmp(self, other: object): if not isinstance(other, self.__class__): raise NotImplementedError("%s != %s" % (other.__class__, self.__class__)) def __eq__(self, other: object): """x.__eq__(y) <==> x==y""" self._check_cmp(other) for attr in self._cmp_attributes: if not getattr(self, attr) == getattr(other, attr): return False return True def __ne__(self, other: object): """x.__ne__(y) <==> x!=y""" self._check_cmp(other) for attr in self._cmp_attributes: if not getattr(self, attr) == getattr(other, attr): return True return False def __lt__(self, other: object): """x.__lt__(y) <==> x<y""" self._check_cmp(other) for attr in self._cmp_attributes: if getattr(self, attr) < getattr(other, attr): return True elif getattr(self, attr) > getattr(other, attr): return False return False def __gt__(self, other: object): """x.__gt__(y) <==> x>y""" self._check_cmp(other) for attr in self._cmp_attributes: if getattr(self, attr) > getattr(other, attr): return True elif getattr(self, attr) < getattr(other, attr): return False return False def __le__(self, other: object): """x.__le__(y) <==> x<=y""" self._check_cmp(other) for attr in self._cmp_attributes: if getattr(self, attr) <= getattr(other, attr): continue else: return False return True def __ge__(self, other: object): """x.__ge__(y) <==> x>=y""" self._check_cmp(other) for attr in self._cmp_attributes: if getattr(self, attr) >= getattr(other, attr): continue else: return False return True def __repr__(self): """ """ return "%s(%s, Value:%s, Length:%d)" % (self.__class__.__name__, self._address, hex( self._value), self._length) def __str__(self): """ """ return "%s(%s, Value:%s, Length:%d)" % (self.__class__.__name__, self._address, hex( self._value), self._length)