Source code for angr.storage.memory_mixins.regioned_memory.region_data

from typing import Optional
from sortedcontainers import SortedDict

from ....errors import SimRegionMapError
from ....state_plugins import SimStatePlugin


[docs]class AddressWrapper: """ AddressWrapper is used in SimAbstractMemory, which provides extra meta information for an address (or a ValueSet object) that is normalized from an integer/BVV/StridedInterval. """ __slots__ = ( "region", "region_base_addr", "address", "is_on_stack", "function_address", )
[docs] def __init__(self, region: str, region_base_addr: int, address, is_on_stack: bool, function_address: Optional[int]): """ Constructor for the class AddressWrapper. :param region: Name of the memory regions it belongs to. :param region_base_addr: Base address of the memory region :param address: An address (not a ValueSet object). :param is_on_stack: Whether this address is on a stack region or not. :param function_address: Related function address (if any). """ self.region = region self.region_base_addr = region_base_addr self.address = address self.is_on_stack = is_on_stack self.function_address = function_address
def __hash__(self): return hash((self.region, self.address)) def __eq__(self, other): return self.region == other.region and self.address == other.address def __repr__(self): return f"<{self.region}> {hex(self.address)}"
[docs] def to_valueset(self, state): """ Convert to a ValueSet instance :param state: A state :return: The converted ValueSet instance """ return state.solver.VS(state.arch.bits, self.region, self.region_base_addr, self.address)
[docs]class RegionDescriptor: """ Descriptor for a memory region ID. """ __slots__ = ( "region_id", "base_address", "related_function_address", )
[docs] def __init__(self, region_id, base_address, related_function_address=None): self.region_id = region_id self.base_address = base_address self.related_function_address = related_function_address
def __repr__(self): return "<{} - {:#x}>".format( self.region_id, self.related_function_address if self.related_function_address is not None else 0 )
[docs]class RegionMap: """ Mostly used in SimAbstractMemory, RegionMap stores a series of mappings between concrete memory address ranges and memory regions, like stack frames and heap regions. """
[docs] def __init__(self, is_stack): """ Constructor :param is_stack: Whether this is a region map for stack frames or not. Different strategies apply for stack regions. """ self.is_stack = is_stack # A sorted list, which maps stack addresses to region IDs self._address_to_region_id = SortedDict() # A dict, which maps region IDs to memory address ranges self._region_id_to_address = {}
# # Properties # def __repr__(self): return "RegionMap<%s>" % ("S" if self.is_stack else "H") @property def is_empty(self): return len(self._address_to_region_id) == 0 @property def stack_base(self): if not self.is_stack: raise SimRegionMapError('Calling "stack_base" on a non-stack region map.') return next(self._address_to_region_id.irange(reverse=True)) @property def region_ids(self): return self._region_id_to_address.keys() # # Public methods # @SimStatePlugin.memo def copy(self, memo): # pylint: disable=unused-argument r = RegionMap(is_stack=self.is_stack) # A shallow copy should be enough, since we never modify any RegionDescriptor object in-place r._address_to_region_id = self._address_to_region_id.copy() r._region_id_to_address = self._region_id_to_address.copy() return r
[docs] def map(self, absolute_address, region_id, related_function_address=None): """ Add a mapping between an absolute address and a region ID. If this is a stack region map, all stack regions beyond (lower than) this newly added regions will be discarded. :param absolute_address: An absolute memory address. :param region_id: ID of the memory region. :param related_function_address: A related function address, mostly used for stack regions. """ if self.is_stack: # Sanity check if not region_id.startswith("stack_"): raise SimRegionMapError('Received a non-stack memory ID "%d" in a stack region map' % region_id) # Remove all stack regions that are lower than the one to add while True: try: addr = next(self._address_to_region_id.irange(maximum=absolute_address, reverse=True)) descriptor = self._address_to_region_id[addr] # Remove this mapping del self._address_to_region_id[addr] # Remove this region ID from the other mapping del self._region_id_to_address[descriptor.region_id] except StopIteration: break else: if absolute_address in self._address_to_region_id: descriptor = self._address_to_region_id[absolute_address] # Remove this mapping del self._address_to_region_id[absolute_address] del self._region_id_to_address[descriptor.region_id] # Add this new region mapping desc = RegionDescriptor(region_id, absolute_address, related_function_address=related_function_address) self._address_to_region_id[absolute_address] = desc self._region_id_to_address[region_id] = desc
[docs] def unmap_by_address(self, absolute_address): """ Removes a mapping based on its absolute address. :param absolute_address: An absolute address """ desc = self._address_to_region_id[absolute_address] del self._address_to_region_id[absolute_address] del self._region_id_to_address[desc.region_id]
[docs] def absolutize(self, region_id, relative_address): """ Convert a relative address in some memory region to an absolute address. :param region_id: The memory region ID :param relative_address: The relative memory offset in that memory region :return: An absolute address if converted, or an exception is raised when region id does not exist. """ if region_id == "global": # The global region always bases 0 return relative_address if region_id not in self._region_id_to_address: raise SimRegionMapError('Non-existent region ID "%s"' % region_id) base_address = self._region_id_to_address[region_id].base_address return base_address + relative_address
[docs] def relativize(self, absolute_address, target_region_id=None): """ Convert an absolute address to the memory offset in a memory region. Note that if an address belongs to heap region is passed in to a stack region map, it will be converted to an offset included in the closest stack frame, and vice versa for passing a stack address to a heap region. Therefore you should only pass in address that belongs to the same category (stack or non-stack) of this region map. :param absolute_address: An absolute memory address :return: A tuple of the closest region ID, the relative offset, and the related function address. """ if target_region_id is None: if self.is_stack: # Get the base address of the stack frame it belongs to base_address = next(self._address_to_region_id.irange(minimum=absolute_address, reverse=False)) else: try: base_address = next(self._address_to_region_id.irange(maximum=absolute_address, reverse=True)) except StopIteration: # Not found. It belongs to the global region then. return "global", absolute_address, None descriptor = self._address_to_region_id[base_address] else: if target_region_id == "global": # Just return the absolute address return "global", absolute_address, None if target_region_id not in self._region_id_to_address: raise SimRegionMapError('Trying to relativize to a non-existent region "%s"' % target_region_id) descriptor = self._region_id_to_address[target_region_id] base_address = descriptor.base_address return descriptor.region_id, absolute_address - base_address, descriptor.related_function_address