# Copyright 2018 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, print_function
# Third party modules
import six
# Own modules
from microprobe.code.var import Variable
from microprobe.exceptions import MicroprobeCodeGenerationError
from microprobe.utils.logger import get_logger
# Constants
LOG = get_logger(__name__)
__all__ = ["MemoryValue", "Address", "InstructionAddress"]
# Functions
# Classes
[docs]class Address(object):
"""Class to represent an address."""
_cmp_attributes = ["_base_address", "_displacement"]
[docs] def __init__(self, base_address=None, displacement=0):
"""
:param base_address: (Default value = None)
:param displacement: (Default value = 0)
"""
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(list(six.string_types) + [Variable]))
@property
def base_address(self):
"""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):
"""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):
"""
: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, six.integer_types):
return self.__class__(self.base_address, self.displacement + other)
else:
raise NotImplementedError
def _check_cmp(self, other):
if not isinstance(other, self.__class__):
raise NotImplementedError(
"%s != %s" % (
other.__class__, self.__class__
)
)
def __eq__(self, other):
"""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):
"""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):
"""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):
"""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):
"""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):
"""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):
""" """
return hash(str(self))
def __iadd__(self, other):
"""
: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, six.integer_types):
return self.__class__(self.base_address, self.displacement + other)
else:
raise NotImplementedError
def __mod__(self, other):
"""
: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, six.integer_types):
if isinstance(self._base_address, six.integer_types):
return (self._base_address + self.displacement) % other
return self.displacement % other
else:
raise NotImplementedError
def __radd__(self, other):
"""
: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, six.integer_types):
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):
"""
: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, six.integer_types):
return self.__class__(self.base_address, self.displacement - other)
else:
print(self.__class__, other.__class__)
raise NotImplementedError
def __str__(self):
""" """
return "%s(%s+0x%016x)" % (
self.__class__.__name__, self.base_address, self.displacement
)
def __sub__(self, other):
"""
: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, six.integer_types):
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]class InstructionAddress(Address):
"""Class to represent an instruction address."""
[docs] def __init__(self, base_address=None, displacement=0, instruction=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):
"""Sets the instruction to which this address is pointing.
:param instruction: Target instruction
:type instruction: :class:`~.Instruction`
"""
self._instruction = instruction
def __add__(self, other):
"""
:param other:
"""
self._instruction = None
return super(InstructionAddress, self).__add__(other)
def __iadd__(self, other):
"""
:param other:
"""
self._instruction = None
return super(InstructionAddress, self).__iadd__(other)
def __mod__(self, other):
"""
:param other:
"""
self._instruction = None
return super(InstructionAddress, self).__mod__(other)
def __radd__(self, other):
"""
:param other:
"""
self._instruction = None
return super(InstructionAddress, self).__radd__(other)
def __rsub__(self, other):
"""
:param other:
"""
self._instruction = None
return super(InstructionAddress, self).__rsub__(other)
def __sub__(self, other):
"""
:param other:
"""
self._instruction = None
return super(InstructionAddress, self).__sub__(other)
[docs]class MemoryValue(object):
"""Class to represent a value in memory."""
_cmp_attributes = ['address', 'value', 'length']
[docs] def __init__(self, address, value, length):
"""
: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):
if not isinstance(other, self.__class__):
raise NotImplementedError(
"%s != %s" % (
other.__class__, self.__class__
)
)
def __eq__(self, other):
"""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):
"""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):
"""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):
"""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):
"""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):
"""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
)