1import struct 2 3from core import ( 4 caching, 5 gettype, 6 lldbwrap, 7 xnu_format, 8) 9from .kmem import KMem, MemoryRange 10from .vm import Pmap 11from .btlog import BTLog, BTLibrary 12from .whatis import * 13 14# FIXME: should not import this from xnu / utils 15from xnu import ( 16 GetSourceInformationForAddress, 17 print_hex_data, 18) 19 20class ZoneBitsMemoryObject(MemoryObject): 21 """ Memory Object for pointers in the Zone Bitmaps range """ 22 23 MO_KIND = "zone bitmap" 24 25 @property 26 def object_range(self): 27 return self.kmem.bits_range 28 29 def describe(self, verbose=False): 30 # 31 # Printing something more useful would require crawling 32 # all zone chunks with non inline bitmaps until we find 33 # the one. 34 # 35 # This is very expensive and really unlikely to ever 36 # be needed for debugging. 37 # 38 # Moreover, bitmap pointers do not leak outside 39 # of the bowels of zalloc, dangling pointers to 40 # this region is very unexpected. 41 # 42 print("Zone Bitmap Info") 43 print(" N/A") 44 print() 45 46 47class ZonePageMetadata(MemoryObject): 48 """ Memory Object for Zone Page Metadata """ 49 50 MO_KIND = "zone metadata" 51 52 def __init__(self, kmem, address): 53 super().__init__(kmem, address) 54 55 if not kmem.meta_range.contains(address): 56 raise IndexError("{:#x} is not inside the meta range {}".format( 57 address, kmem.meta_range)) 58 59 # 60 # Resolve the ZPM we fall into 61 # 62 size = kmem.zpm_type.GetByteSize() 63 idx = (address - kmem.meta_range.start) // size 64 sbv = kmem.target.xCreateValueFromAddress(None, 65 kmem.meta_range.start + idx * size, kmem.zpm_type) 66 chunk_len = sbv.xGetIntegerByName('zm_chunk_len') 67 68 self.mo_sbv = sbv 69 self.kmem = kmem 70 71 # 72 # Compute the canonical ZPM 73 # 74 # 0xe = ZM_SECONDARY_PAGE 75 # 0xf = ZM_SECONDARY_PCPU_PAGE 76 # 77 # TODO use a nice package to index enums by name, 78 # can't use GetEnumName() because it uses kern.* 79 # 80 if chunk_len in (0xe, 0xf): 81 pg_idx = sbv.xGetIntegerByName('zm_page_index') 82 idx -= pg_idx 83 sbv = sbv.xGetSiblingValueAtIndex(-pg_idx) 84 chunk_len = sbv.xGetIntegerByName('zm_chunk_len') 85 86 self.sbv = sbv 87 self._idx = idx 88 self._chunk_len = chunk_len 89 90 @classmethod 91 def _create_with_zone_address(cls, kmem, address): 92 zone_range = kmem.zone_range 93 if not zone_range.contains(address): 94 raise IndexError("{:#x} is not inside the zone map {}".format( 95 address, zone_range)) 96 97 index = (address - zone_range.start) >> kmem.page_shift 98 meta_addr = kmem.meta_range.start + index * kmem.zpm_type.GetByteSize() 99 100 return ZonePageMetadata(kmem, meta_addr) 101 102 @classmethod 103 def _create_with_pva(cls, kmem, pva): 104 address = ((pva | 0xffffffff00000000) << kmem.page_shift) & 0xffffffffffffffff 105 return ZonePageMetadata._create_with_zone_address(kmem, address) 106 107 @property 108 def object_range(self): 109 addr = self.sbv.GetLoadAddress() 110 clen = self._chunk_len 111 if clen == 1 and self.zone.percpu: 112 clen = self.kmem.ncpus 113 size = self._chunk_len * self.kmem.zpm_type.GetByteSize() 114 115 return MemoryRange(addr, addr + size) 116 117 @property 118 def zone(self): 119 sbv = self.sbv 120 return Zone(sbv.xGetIntegerByName('zm_index')) 121 122 @property 123 def pgz_slot(self): 124 addr = self.page_addr 125 kmem = self.kmem 126 if kmem.pgz_range.contains(addr): 127 return (addr - kmem.pgz_range.start) >> (kmem.page_shift + 1) 128 return None 129 130 def _pgz_alloc_frames(self, index): 131 kmem = self.kmem 132 target = kmem.target 133 bt = kmem.pgz_bt.xGetSiblingValueAtIndex(index) 134 return ( 135 kmem.stext + pc 136 for pc in target.xIterAsInt32( 137 bt.xGetLoadAddressByName('pgz_bt'), 138 bt.xGetIntegerByName('pgz_depth') 139 ) 140 ) 141 142 @property 143 def pgz_alloc_bt_frames(self): 144 return self._pgz_alloc_frames(2 * self.pgz_slot) 145 146 @property 147 def pgz_free_bt_frames(self): 148 return self._pgz_alloc_frames(2 * self.pgz_slot + 1) 149 150 def describe(self, verbose=False): 151 kmem = self.kmem 152 sbv = self.sbv 153 zone = self.zone 154 155 chunk_len = self._chunk_len 156 if zone.percpu: 157 chunk_len = kmem.ncpus 158 159 zone.describe() 160 161 print("Zone Metadata Info") 162 print(" chunk length : {}".format(chunk_len)) 163 print(" metadata : {:#x}".format(sbv.GetLoadAddress())) 164 print(" page : {:#x}".format(self.page_addr)) 165 166 if sbv.xGetIntegerByName('zm_inline_bitmap'): 167 if verbose: 168 bitmap = [ 169 "{:#010x}".format(sbv.xGetSiblingValueAtIndex(i).xGetIntegerByName('zm_bitmap')) 170 for i in range(self._chunk_len) 171 ] 172 print(" bitmap : inline [ {} ]".format(" ".join(bitmap))) 173 else: 174 print(" bitmap : inline") 175 else: 176 bref = sbv.xGetIntegerByName('zm_bitmap') 177 blen = 1 << ((bref >> 29) & 0x7) 178 bsize = blen << 3 179 baddr = kmem.bits_range.start + 8 * (bref & 0x0fffffff) 180 bitmap = ( 181 "{:#018x}".format(word) 182 for word in kmem.target.xIterAsUInt64(baddr, blen) 183 ) 184 185 if bref == 0: 186 print(" bitmap : None") 187 elif not verbose: 188 print(" bitmap : {:#x} ({} bytes)".format(baddr, bsize)) 189 elif blen <= 2: 190 print(" bitmap : {:#x} ({} bytes) [ {} ]".format( 191 baddr, bsize, ' '.join(bitmap))) 192 else: 193 print(" bitmap : {:#x} ({} bytes) [".format(baddr, bsize)) 194 for i in range(blen // 4): 195 print(" {} {} {} {}".format( 196 next(bitmap), next(bitmap), 197 next(bitmap), next(bitmap))) 198 print(" ]") 199 200 print() 201 202 mo_sbv = self.mo_sbv 203 if sbv != mo_sbv: 204 pg_idx = self.mo_sbv.xGetIntegerByName('zm_page_index') 205 206 print("Secondary Metadata Info") 207 print(" index : {}/{}".format(pg_idx + 1, chunk_len)) 208 print(" metadata : {:#x}".format(mo_sbv.GetLoadAddress())) 209 print(" page : {:#x}".format( 210 self.page_addr + (pg_idx << kmem.page_shift))) 211 print() 212 213 if verbose: 214 print("-" * 80) 215 print() 216 print(str(self.mo_sbv)) 217 print() 218 219 220 @property 221 def next_pva(self): 222 """ the next zone_pva_t queued after this Zone Page Metadata """ 223 224 return self.sbv.xGetIntegerByPath('.zm_page_next.packed_address') 225 226 @property 227 def page_addr(self): 228 """ The page address corresponding to this Zone Page Metadata """ 229 230 kmem = self.kmem 231 return kmem.zone_range.start + (self._idx << kmem.page_shift) 232 233 def iter_all(self, zone): 234 """ All element addresses covered by this chunk """ 235 236 base = self.page_addr 237 esize = zone.elem_outer_size 238 offs = zone.elem_inner_offs 239 count = zone.chunk_elems 240 run = self.sbv.xGetIntegerByName('zm_chunk_len') 241 242 return range(base + offs, base + (run << self.kmem.page_shift), esize) 243 244 def is_allocated(self, zone, addr): 245 """ Whether an address has the allocated bit set """ 246 247 if not self._chunk_len: 248 return False 249 250 sbv = self.sbv 251 base = self.page_addr + zone.elem_inner_offs 252 esize = zone.elem_inner_size 253 idx = (addr - base) // esize 254 255 if sbv.xGetIntegerByName('zm_inline_bitmap'): 256 w, b = divmod(idx, 32) 257 mask = sbv.xGetSiblingValueAtIndex(w).xGetIntegerByName('zm_bitmap') 258 return (mask & (1 << b)) == 0 259 else: 260 w, b = divmod(idx, 64) 261 bref = sbv.xGetIntegerByName('zm_bitmap') 262 kmem = self.kmem 263 baddr = kmem.bits_range.start + 8 * (bref & 0x0fffffff) + 8 * w 264 return not (kmem.target.xReadUInt64(baddr) & (1 << b)) 265 266 def iter_allocated(self, zone): 267 """ All allocated addresses in this this chunk """ 268 269 kmem = self.kmem 270 sbv = self.sbv 271 base = self.page_addr 272 273 # cache memory, can make enumeration twice as fast for smaller objects 274 sbv.target.xReadBytes(base, self._chunk_len << kmem.page_shift) 275 276 esize = zone.elem_outer_size 277 base += zone.elem_inner_offs 278 279 if sbv.xGetIntegerByName('zm_inline_bitmap'): 280 for i in range(zone.chunk_elems): 281 w, b = divmod(i, 32) 282 if b == 0: 283 mask = sbv.xGetSiblingValueAtIndex(w).xGetIntegerByName('zm_bitmap') 284 if not mask & (1 << b): 285 yield base + i * esize 286 else: 287 bref = sbv.xGetIntegerByName('zm_bitmap') 288 baddr = kmem.bits_range.start + 8 * (bref & 0x0fffffff) 289 data = kmem.target.xIterAsUInt64(baddr, 1 << ((bref >> 29) & 0x7)) 290 291 for i in range(zone.chunk_elems): 292 b = i & 63 293 if b == 0: 294 word = next(data) 295 if not word & (1 << b): 296 yield base + i * esize 297 298 299class ZoneHeapMemoryObject(MemoryObject): 300 """ Memory Object for zone allocated objects """ 301 302 MO_KIND = "zone heap" 303 304 def __init__(self, kmem, address): 305 super().__init__(kmem, address) 306 307 if not kmem.zone_range.contains(address): 308 raise IndexError("{:#x} is not inside the zone range {}".format( 309 address, kmem.zone_range)) 310 311 meta = ZonePageMetadata._create_with_zone_address(kmem, address) 312 zone = meta.zone 313 esize = zone.elem_outer_size 314 315 if kmem.pgz_range.contains(address): 316 real_addr = meta.sbv.xGetIntegerByName('zm_pgz_orig_addr') 317 page_mask = kmem.page_mask 318 elem_addr = (real_addr & page_mask) + (address & ~page_mask) 319 elem_idx = ((elem_addr & page_mask) - zone.elem_inner_offs) // esize 320 self.real_addr = real_addr 321 self.real_meta = ZonePageMetadata._create_with_zone_address(kmem, real_addr) 322 self.pgz = True 323 else: 324 base = meta.page_addr + zone.elem_inner_offs 325 elem_idx = (address - base) // esize if address >= base else -1 326 elem_addr = base + elem_idx * esize if address >= base else None 327 self.real_addr = elem_addr 328 self.real_meta = meta 329 self.pgz = False 330 331 self.kmem = kmem 332 self.meta = meta 333 self.zone = zone 334 self.elem_idx = elem_idx 335 self.elem_addr = elem_addr 336 337 @property 338 def object_range(self): 339 if self.elem_idx >= 0: 340 elem_addr = self.elem_addr 341 elem_size = self.zone.elem_outer_size 342 return MemoryRange(elem_addr, elem_addr + elem_size) 343 344 base = self.meta.page_addr 345 size = self.zone.elem_inner_offs 346 return MemoryRange(base, base + size) 347 348 @property 349 def status(self): 350 zone = self.zone 351 real_addr = self.real_addr 352 353 if self.elem_idx < 0: 354 return "invalid" 355 356 elif not self.real_meta.is_allocated(zone, real_addr): 357 return "free" 358 359 elif real_addr in zone.cached(): 360 return "free (cached)" 361 362 elif real_addr in zone.recirc(): 363 return "free (recirc)" 364 365 else: 366 return "allocated" 367 368 def hexdump(self): 369 print("Hexdump:") 370 371 target = self.kmem.target 372 zone = self.zone 373 eaddr = self.elem_addr 374 eend = eaddr + zone.elem_inner_size 375 delta = self.real_addr - eaddr 376 377 rz = zone.elem_redzone 378 start = (eaddr & -16) - min(rz, 16) - 16 379 end = (eend + 16 + 15) & -16 380 marks = { self.address: '>' } 381 phex = print_hex_data 382 383 384 if rz > 16: 385 print(" " + "=" * 88) 386 print(" {}".format("." * 18)) 387 388 try: 389 data = target.xReadBytes(start + delta, eaddr - start) 390 phex(data, start, "", marks) 391 except: 392 print(" *** unable to read redzone memory ***") 393 else: 394 try: 395 data = target.xReadBytes(start + delta, eaddr - rz - start) 396 phex(data, start, "", marks) 397 except: 398 pass 399 400 print(" " + "=" * 88) 401 402 if rz: 403 try: 404 data = target.xReadBytes(eaddr - rz + delta, rz) 405 phex(data, eaddr - rz, "", marks) 406 except: 407 print(" *** unable to read redzone memory ***") 408 409 if rz: 410 print(" {}".format("-" * 88)) 411 412 try: 413 data = target.xReadBytes(eaddr + delta, eend - eaddr) 414 phex(data, eaddr, "", marks) 415 except: 416 print(" *** unable to read element memory ***") 417 418 print(" " + "=" * 88) 419 420 try: 421 data = target.xReadBytes(eend + delta, end - eend) 422 phex(data, eend, "", marks) 423 except: 424 pass 425 426 print() 427 428 def describe(self, verbose=False): 429 meta = self.meta 430 zone = self.zone 431 status = self.status 432 btlog = zone.btlog 433 434 meta.describe() 435 436 print("Zone Heap Object Info") 437 438 print(" element index : {}".format(self.elem_idx)) 439 print(" chunk offset : {}".format(self.address - meta.page_addr)) 440 print(" status : {}".format(status)) 441 if self.pgz: 442 print(" pgz orig address : {:#x}".format(self.real_addr)) 443 print() 444 445 print("PGZ Allocation backtrace:") 446 for pc in meta.pgz_alloc_bt_frames: 447 print(" " + GetSourceInformationForAddress(pc)) 448 449 if status == 'free': 450 print() 451 452 print("PGZ Free backtrace:") 453 for pc in meta.pgz_free_bt_frames: 454 print(" " + GetSourceInformationForAddress(pc)) 455 elif btlog and (btlog.is_log() or status == 'allocated'): 456 record = next(btlog.iter_records( 457 wantElement=self.elem_addr, reverse=True), None) 458 if record: 459 btlib = BTLibrary.get_shared() 460 print(" last zlog backtrace", 461 *btlib.get_stack(record.ref).symbolicated_frames(prefix=" "), sep="\n") 462 463 print() 464 465 if self.elem_idx >= 0 and verbose: 466 self.hexdump() 467 468 469@whatis_provider 470class ZoneWhatisProvider(WhatisProvider): 471 """ 472 Whatis Provider for the zone ranges 473 - metadata (bits and ZPM) 474 - PGZ 475 - regular heap objects 476 """ 477 478 def __init__(self, kmem): 479 super().__init__(kmem) 480 481 def claims(self, address): 482 kmem = self.kmem 483 484 return any( 485 r.contains(address) 486 for r in (kmem.meta_range, kmem.bits_range, kmem.zone_range) 487 ) 488 489 def lookup(self, address): 490 kmem = self.kmem 491 492 if kmem.meta_range.contains(address): 493 return ZonePageMetadata(self.kmem, address) 494 495 if kmem.bits_range.contains(address): 496 return ZoneBitsMemoryObject(self.kmem, address) 497 498 return ZoneHeapMemoryObject(self.kmem, address) 499 500 501class ZPercpuValue(object): 502 """ 503 Provides an enumerator for a zpercpu value 504 """ 505 506 def __init__(self, sbvalue): 507 """ 508 @param sbvalue (SBValue) 509 The value to enumerate 510 """ 511 self.sbv = sbvalue 512 513 def __iter__(self): 514 sbv = self.sbv 515 kmem = KMem.get_shared() 516 addr = sbv.GetValueAsAddress() 517 name = sbv.GetName() 518 ty = sbv.GetType().GetPointeeType() 519 520 return ( 521 sbv.xCreateValueFromAddress(name, addr + (cpu << kmem.page_shift), ty) 522 for cpu in kmem.zcpus 523 ) 524 525 526class Zone(object): 527 """ 528 the Zone class wraps XNU Zones and provides fast enumeration 529 of allocated, cached, ... elements. 530 """ 531 532 def __init__(self, index_name_or_addr): 533 """ 534 @param index_name_or_addr (int or str): 535 - int: a zone index within [0, num_zones) 536 - int: a zone address within [zone_array, zone_array + num_zones) 537 - str: a zone name 538 539 @param kmem (KMem or None) 540 The kmem this command applies to, 541 or None for the current one 542 """ 543 544 kmem = KMem.get_shared() 545 zarr = kmem.zone_array 546 547 if isinstance(index_name_or_addr, str): 548 mangled_name = index_name_or_addr.replace(' ', '.') 549 zid = self._find_zone_id_by_mangled_name(mangled_name) 550 elif index_name_or_addr <= kmem.num_zones: 551 zid = index_name_or_addr 552 else: 553 zid = index_name_or_addr - zarr.GetLoadAddress() 554 zid = zid // zarr.GetType().GetArrayElementType().GetByteSize() 555 556 self.kmem = kmem 557 self.zid = zid 558 self.sbv = zarr.chkGetChildAtIndex(zid) 559 560 @staticmethod 561 @caching.cache_dynamically 562 def get_zone_name(zid, target=None): 563 """ 564 Returns a zone name by index. 565 566 @param zid (int 567 A zone ID 568 569 @returns (str or None) 570 Returns a string holding the zone name 571 if the zone exists, or None 572 """ 573 574 kmem = KMem.get_shared() 575 if zid >= kmem.num_zones: 576 return None 577 578 zone = kmem.zone_array.chkGetChildAtIndex(zid) 579 zsec = kmem.zsec_array.chkGetChildAtIndex(zid) 580 581 if zone.xGetIntegerByName('z_self') == 0: 582 return None 583 584 heap_id = zsec.xGetIntegerByName('z_kheap_id') 585 586 return KMem._HEAP_NAMES[heap_id] + zone.xGetCStringByName('z_name') 587 588 @staticmethod 589 @caching.cache_dynamically 590 def _find_zone_id_by_mangled_name(name, target=None): 591 """ 592 Lookup a zone ID by name 593 594 @param name (str) 595 The name of the zone to lookup 596 597 @returns (int) 598 The zone ID for this name 599 """ 600 601 kmem = KMem.get_shared() 602 for zid in range(kmem.num_zones): 603 k = Zone.get_zone_name(zid) 604 if k is not None and name == k.replace(' ', '.'): 605 return zid 606 607 raise KeyError("No zone called '{}' found".format(name)) 608 609 @property 610 def initialized(self): 611 """ The zone name """ 612 613 return self.sbv.xGetIntegerByName('z_self') != 0 614 615 @property 616 def address(self): 617 """ The zone address """ 618 619 return self.sbv.GetLoadAddress() 620 621 @property 622 def name(self): 623 """ The zone name """ 624 625 return self.get_zone_name(self.zid) 626 627 @property 628 def mangled_name(self): 629 """ The zone mangled name """ 630 631 return self.name.replace(' ', '.') 632 633 @caching.dyn_cached_property 634 def elem_redzone(self, target=None): 635 """ The inner size of elements """ 636 637 if self.kmem.kasan_classic: 638 return self.sbv.xGetIntegerByName('z_kasan_redzone') 639 return 0 640 641 @caching.dyn_cached_property 642 def elem_inner_size(self, target=None): 643 """ The inner size of elements """ 644 645 return self.sbv.xGetIntegerByName('z_elem_size') 646 647 @caching.dyn_cached_property 648 def elem_outer_size(self, target=None): 649 """ The size of elements """ 650 651 if not self.kmem.kasan_classic: 652 return self.elem_inner_size 653 return self.elem_inner_size + self.elem_redzone 654 655 @caching.dyn_cached_property 656 def elem_inner_offs(self, target=None): 657 """ The chunk initial offset """ 658 659 return self.sbv.xGetIntegerByName('z_elem_offs') 660 661 @caching.dyn_cached_property 662 def chunk_pages(self, target=None): 663 """ The number of pages per chunk """ 664 665 return self.sbv.xGetIntegerByName('z_chunk_pages') 666 667 @caching.dyn_cached_property 668 def chunk_elems(self, target=None): 669 """ The number of elements per chunk """ 670 671 return self.sbv.xGetIntegerByName('z_chunk_elems') 672 673 @property 674 def percpu(self): 675 """ Whether this is a per-cpu zone """ 676 677 return self.sbv.xGetIntegerByName('z_percpu') 678 679 @property 680 def btlog(self): 681 """ Returns the zone's BTLog or None """ 682 683 try: 684 btlog = self.sbv.xGetPointeeByName('z_btlog') 685 return BTLog(btlog) 686 except: 687 return None 688 689 def describe(self): 690 kmem = self.kmem 691 zone = self.sbv 692 zsec = kmem.zsec_array.chkGetChildAtIndex(self.zid) 693 694 submap_arr = kmem.target.chkFindFirstGlobalVariable('zone_submaps_names') 695 submap_idx = zsec.xGetIntegerByName('z_submap_idx') 696 submap_name = submap_arr.xGetCStringAtIndex(submap_idx) 697 submap_end = zsec.xGetIntegerByName('z_submap_from_end') 698 699 try: 700 btlog = zone.xGetIntegerByName('z_btlog') 701 except: 702 # likely a release kernel 703 btlog = None 704 705 fmt = ( 706 "Zone Info\n" 707 " name : {0.name} ({&z:#x})\n" 708 " submap : {1} (from {2})\n" 709 " element size : {0.elem_inner_size}\n" 710 " element offs : {0.elem_inner_offs}\n" 711 ) 712 if kmem.kasan_classic: 713 fmt += " element redzone : {0.elem_redzone}\n" 714 fmt += " chunk elems / pages : {$z.z_chunk_elems} / {$z.z_chunk_pages}\n" 715 if btlog: 716 fmt += " btlog : {$z.z_btlog:#x}\n" 717 718 print(xnu_format(fmt, self, submap_name, 719 "right" if submap_end else "left", z = zone)); 720 721 def iter_page_queue(self, name): 722 kmem = self.kmem 723 zone = self.sbv 724 725 pva = zone.xGetIntegerByPath('.{}.packed_address'.format(name)) 726 727 while pva: 728 meta = ZonePageMetadata._create_with_pva(kmem, pva) 729 pva = meta.next_pva 730 yield meta 731 732 def _depotElements(self, depot, into): 733 last = depot.xGetPointeeByName('zd_tail').GetValueAsAddress() 734 mag = depot.xGetPointeeByName('zd_head') 735 736 kmem = self.kmem 737 n = kmem.mag_size 738 target = kmem.target 739 740 while mag and mag.GetLoadAddress() != last: 741 into.update(kmem.iter_addresses(target.xIterAsULong( 742 mag.xGetLoadAddressByName('zm_elems'), 743 n 744 ))) 745 mag = mag.xGetPointeeByName('zm_next') 746 747 return into 748 749 def cached(self, into = None): 750 """ all addresses in per-cpu caches or per-cpu depots """ 751 752 pcpu = self.sbv.GetChildMemberWithName('z_pcpu_cache') 753 into = into if into is not None else set() 754 755 if pcpu.GetValueAsAddress(): 756 target = pcpu.target 757 kmem = self.kmem 758 759 for cache in ZPercpuValue(pcpu): 760 into.update(kmem.iter_addresses(target.xIterAsULong( 761 cache.xGetIntegerByName('zc_alloc_elems'), 762 cache.xGetIntegerByName('zc_alloc_cur') 763 ))) 764 765 into.update(kmem.iter_addresses(target.xIterAsULong( 766 cache.xGetIntegerByName('zc_free_elems'), 767 cache.xGetIntegerByName('zc_free_cur') 768 ))) 769 770 self._depotElements( 771 cache.chkGetChildMemberWithName('zc_depot'), 772 into = into 773 ) 774 775 return into 776 777 def recirc(self, into = None): 778 """ all addresses in the recirculation layer """ 779 780 return self._depotElements( 781 self.sbv.chkGetChildMemberWithName('z_recirc'), 782 into = into if into is not None else set() 783 ) 784 785 def iter_all(self, ty = None): 786 """ 787 Returns a generator for all addresses/values that can be made 788 789 @param ty (SBType or None) 790 An optional type to use to form SBValues 791 792 @returns 793 - (generator<int>) if ty is None 794 - (generator<SBValue>) if ty is set 795 """ 796 797 addresses = ( 798 addr 799 for name in ( 800 'z_pageq_full', 801 'z_pageq_partial', 802 'z_pageq_empty', 803 ) 804 for meta in self.iter_page_queue(name) 805 for addr in meta.iter_all(self) 806 ) 807 808 if ty is None: 809 return addresses 810 811 fn = self.kmem.target.xCreateValueFromAddress 812 return (fn('e', addr, ty) for addr in addresses) 813 814 def iter_free(self, ty = None): 815 """ 816 Returns a generator for all free addresses/values 817 818 @param ty (SBType or None) 819 An optional type to use to form SBValues 820 821 @returns 822 - (generator<int>) if ty is None 823 - (generator<SBValue>) if ty is set 824 """ 825 826 cached = set() 827 self.cached(into = cached) 828 self.recirc(into = cached) 829 830 addresses = ( 831 addr 832 for name in ( 833 'z_pageq_full', 834 'z_pageq_partial', 835 ) 836 for meta in self.iter_page_queue(name) 837 for addr in meta.iter_all(self) 838 if addr in cached or not meta.is_allocated(self, addr) 839 ) 840 841 if ty is None: 842 return addresses 843 844 fn = self.kmem.target.xCreateValueFromAddress 845 return (fn('e', addr, ty) for addr in addresses) 846 847 def iter_allocated(self, ty = None): 848 """ 849 Returns a generator for all allocated addresses/values 850 851 @param ty (SBType or None) 852 An optional type to use to form SBValues 853 854 @returns 855 - (generator<int>) if ty is None 856 - (generator<SBValue>) if ty is set 857 """ 858 859 cached = set() 860 self.cached(into = cached) 861 self.recirc(into = cached) 862 863 addresses = ( 864 addr 865 for name in ( 866 'z_pageq_full', 867 'z_pageq_partial', 868 ) 869 for meta in self.iter_page_queue(name) 870 for addr in meta.iter_allocated(self) 871 if addr not in cached 872 ) 873 874 if ty is None: 875 return addresses 876 877 fn = self.kmem.target.xCreateValueFromAddress 878 return (fn('e', addr, ty) for addr in addresses) 879 880 def __iter__(self): 881 return self.iter_allocated() 882 883 884__all__ = [ 885 ZPercpuValue.__name__, 886 Zone.__name__, 887] 888