@@ -280,7 +280,7 @@ def restore(self, mem_dict):
280280 self .ql .log .debug (f'restoring memory range: { lbound :#08x} { ubound :#08x} { label } ' )
281281
282282 size = ubound - lbound
283- if not self .is_mapped (lbound , size ):
283+ if self .is_available (lbound , size ):
284284 self .ql .log .debug (f'mapping { lbound :#08x} { ubound :#08x} , mapsize = { size :#x} ' )
285285 self .map (lbound , size , perms , label )
286286
@@ -420,9 +420,34 @@ def unmap_all(self):
420420 for begin , end , _ in self .ql .uc .mem_regions ():
421421 self .unmap (begin , end - begin + 1 )
422422
423+ def __mapped_regions (self ) -> Iterator [Tuple [int , int ]]:
424+ """Iterate through all mapped memory regions, consolidating adjacent regions
425+ together to a continuous one. Protection bits and labels are ignored.
426+ """
427+
428+ if not self .map_info :
429+ return
430+
431+ iter_memmap = iter (self .map_info )
432+
433+ p_lbound , p_ubound , _ , _ , _ = next (iter_memmap )
434+
435+ # map_info is assumed to contain non-overlapping regions sorted by lbound
436+ for lbound , ubound , _ , _ , _ in iter_memmap :
437+ if lbound == p_ubound :
438+ p_ubound = ubound
439+ else :
440+ yield (p_lbound , p_ubound )
441+
442+ p_lbound = lbound
443+ p_ubound = ubound
444+
445+ yield (p_lbound , p_ubound )
446+
447+
423448 def is_available (self , addr : int , size : int ) -> bool :
424449 """Query whether the memory range starting at `addr` and is of length of `size` bytes
425- can be allocated .
450+ is available for allocation .
426451
427452 Returns: True if it can be allocated, False otherwise
428453 """
@@ -433,16 +458,21 @@ def is_available(self, addr: int, size: int) -> bool:
433458 end = addr + size
434459
435460 # make sure neither begin nor end are enclosed within a mapped range, or entirely enclosing one
436- return not any ((lbound <= begin < ubound ) or (lbound < end <= ubound ) or (begin <= lbound < ubound <= end ) for lbound , ubound , _ , _ , _ in self .map_info )
461+ return not any ((lbound <= begin < ubound ) or (lbound < end <= ubound ) or (begin <= lbound < ubound <= end ) for lbound , ubound in self .__mapped_regions () )
437462
438463 def is_mapped (self , addr : int , size : int ) -> bool :
439464 """Query whether the memory range starting at `addr` and is of length of `size` bytes
440- is mapped, either partially or entirely .
465+ is fully mapped .
441466
442- Returns: True if any part of the specified memory range is taken, False otherwise
467+ Returns: True if the specified memory range is taken fully , False otherwise
443468 """
444469
445- return not self .is_available (addr , size )
470+ assert size > 0 , 'expected a positive size value'
471+
472+ begin = addr
473+ end = addr + size
474+
475+ return any ((lbound <= begin < end <= ubound ) for lbound , ubound in self .__mapped_regions ())
446476
447477 def find_free_space (self , size : int , minaddr : int = None , maxaddr : int = None , align : int = None ) -> int :
448478 """Locate an unallocated memory that is large enough to contain a range in size of
0 commit comments