FLEXHeapEnumerator.m 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. //
  2. // FLEXHeapEnumerator.m
  3. // Flipboard
  4. //
  5. // Created by Ryan Olson on 5/28/14.
  6. // Copyright (c) 2014 Flipboard. All rights reserved.
  7. //
  8. #import "FLEXHeapEnumerator.h"
  9. #import <malloc/malloc.h>
  10. #import <mach/mach.h>
  11. #import <objc/runtime.h>
  12. static CFMutableSetRef registeredClasses;
  13. // Mimics the objective-c object stucture for checking if a range of memory is an object.
  14. typedef struct {
  15. Class isa;
  16. } flex_maybe_object_t;
  17. @implementation FLEXHeapEnumerator
  18. static void range_callback(task_t task, void *context, unsigned type, vm_range_t *ranges, unsigned rangeCount)
  19. {
  20. flex_object_enumeration_block_t block = (__bridge flex_object_enumeration_block_t)context;
  21. if (!block) {
  22. return;
  23. }
  24. for (unsigned int i = 0; i < rangeCount; i++) {
  25. vm_range_t range = ranges[i];
  26. flex_maybe_object_t *tryObject = (flex_maybe_object_t *)range.address;
  27. Class tryClass = NULL;
  28. #ifdef __arm64__
  29. // See http://www.sealiesoftware.com/blog/archive/2013/09/24/objc_explain_Non-pointer_isa.html
  30. extern uint64_t objc_debug_isa_class_mask WEAK_IMPORT_ATTRIBUTE;
  31. tryClass = (__bridge Class)((void *)((uint64_t)tryObject->isa & objc_debug_isa_class_mask));
  32. #else
  33. tryClass = tryObject->isa;
  34. #endif
  35. // If the class pointer matches one in our set of class pointers from the runtime, then we should have an object.
  36. if (CFSetContainsValue(registeredClasses, (__bridge const void *)(tryClass))) {
  37. block((__bridge id)tryObject, tryClass);
  38. }
  39. }
  40. }
  41. + (void)enumerateLiveObjectsUsingBlock:(flex_object_enumeration_block_t)block
  42. {
  43. if (!block) {
  44. return;
  45. }
  46. // Refresh the class list on every call in case classes are added to the runtime.
  47. [self updateRegisteredClasses];
  48. // Inspired by:
  49. // http://llvm.org/svn/llvm-project/lldb/tags/RELEASE_34/final/examples/darwin/heap_find/heap/heap_find.cpp
  50. // https://gist.github.com/samdmarshall/17f4e66b5e2e579fd396
  51. vm_address_t *zones = NULL;
  52. unsigned int zoneCount = 0;
  53. kern_return_t result = malloc_get_all_zones(TASK_NULL, NULL, &zones, &zoneCount);
  54. if (result == KERN_SUCCESS) {
  55. for (unsigned int i = 0; i < zoneCount; i++) {
  56. malloc_zone_t *zone = (malloc_zone_t *)zones[i];
  57. if (zone->introspect && zone->introspect->enumerator) {
  58. zone->introspect->enumerator(TASK_NULL, (__bridge void *)block, MALLOC_PTR_IN_USE_RANGE_TYPE, (vm_address_t)zone, NULL, &range_callback);
  59. }
  60. }
  61. }
  62. }
  63. + (void)updateRegisteredClasses
  64. {
  65. if (!registeredClasses) {
  66. registeredClasses = CFSetCreateMutable(NULL, 0, NULL);
  67. } else {
  68. CFSetRemoveAllValues(registeredClasses);
  69. }
  70. unsigned int count = 0;
  71. Class *classes = objc_copyClassList(&count);
  72. for (unsigned int i = 0; i < count; i++) {
  73. CFSetAddValue(registeredClasses, (__bridge const void *)(classes[i]));
  74. }
  75. free(classes);
  76. }
  77. @end