def Regions(self,
              skip_executable_regions=False,
              skip_shared_regions=False,
              skip_readonly_regions=False):
    """Iterates over the readable regions for this process.

    We use mach_vm_region_recurse here to get a fine grained view of
    the process' memory space. The algorithm is that for some regions,
    the function returns is_submap=True which means that there are
    actually subregions that we need to examine by increasing the
    depth and calling the function again. For example, there are two
    regions, addresses 1000-2000 and 2000-3000 where 1000-2000 has two
    subregions, 1100-1200 and 1300-1400. In that case we would call:

    mvrr(address=0, depth=0)       -> (1000-2000, is_submap=True)
    mvrr(address=0, depth=1)       -> (1100-1200, is_submap=False)
    mvrr(address=1200, depth=1)    -> (1300-1400, is_submap=False)
    mvrr(address=1400, depth=1)    -> (2000-3000, is_submap=False)

    At this point, we know we went out of the original submap which
    ends at 2000. We need to recheck the region at 2000, it could be
    submap = True at depth 0 so we call

    mvrr(address=1400, depth=0)    -> (2000-3000, is_submap=False)

    Args:
      skip_executable_regions: Skips executable sections.
      skip_shared_regions: Skips shared sections. Includes mapped files.
      skip_readonly_regions: Skips readonly sections.

    Yields:
      Pairs (address, length) for each identified region.
    """

    address = ctypes.c_ulong(0)
    mapsize = ctypes.c_ulong(0)
    count = ctypes.c_uint32(submap_info_size)
    sub_info = vm_region_submap_short_info_data_64()
    depth = 0
    depth_end_addresses = {}

    while True:
      c_depth = ctypes.c_uint32(depth)

      r = libc.mach_vm_region_recurse(self.task, ctypes.pointer(address),
                                      ctypes.pointer(mapsize),
                                      ctypes.pointer(c_depth),
                                      ctypes.pointer(sub_info),
                                      ctypes.pointer(count))

      # If we get told "invalid address", we have crossed into kernel land...
      if r == 1:
        break

      if r != 0:
        raise process_error.ProcessError("Error in mach_vm_region, ret=%s" % r)

      if depth > 0 and address.value >= depth_end_addresses[depth]:
        del depth_end_addresses[depth]
        depth -= 1
        continue

      p = sub_info.protection
      if skip_executable_regions and p & VM_PROT_EXECUTE:
        address.value += mapsize.value
        continue

      if skip_shared_regions and sub_info.share_mode in [
          SM_COW, SM_SHARED, SM_TRUESHARED
      ]:
        address.value += mapsize.value
        continue

      if not p & VM_PROT_READ:
        address.value += mapsize.value
        continue

      writable = p & VM_PROT_WRITE
      if skip_readonly_regions and not writable:
        address.value += mapsize.value
        continue

      if sub_info.is_submap:
        depth += 1
        depth_end_addresses[depth] = address.value + mapsize.value
      else:
        yield address.value, mapsize.value
        address.value += mapsize.value
Iterates over the readable regions for this process.

    We use mach_vm_region_recurse here to get a fine grained view of
    the process' memory space. The algorithm is that for some regions,
    the function returns is_submap=True which means that there are
    actually subregions that we need to examine by increasing the
    depth and calling the function again. For example, there are two
    regions, addresses 1000-2000 and 2000-3000 where 1000-2000 has two
    subregions, 1100-1200 and 1300-1400. In that case we would call:

    mvrr(address=0, depth=0)       -> (1000-2000, is_submap=True)
    mvrr(address=0, depth=1)       -> (1100-1200, is_submap=False)
    mvrr(address=1200, depth=1)    -> (1300-1400, is_submap=False)
    mvrr(address=1400, depth=1)    -> (2000-3000, is_submap=False)

    At this point, we know we went out of the original submap which
    ends at 2000. We need to recheck the region at 2000, it could be
    submap = True at depth 0 so we call

    mvrr(address=1400, depth=0)    -> (2000-3000, is_submap=False)

    Args:
      skip_executable_regions: Skips executable sections.
      skip_shared_regions: Skips shared sections. Includes mapped files.
      skip_readonly_regions: Skips readonly sections.

    Yields:
      Pairs (address, length) for each identified region.