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