diff options
Diffstat (limited to 'lldb/examples/darwin/heap_find/heap/heap_find.cpp')
-rw-r--r-- | lldb/examples/darwin/heap_find/heap/heap_find.cpp | 1470 |
1 files changed, 655 insertions, 815 deletions
diff --git a/lldb/examples/darwin/heap_find/heap/heap_find.cpp b/lldb/examples/darwin/heap_find/heap/heap_find.cpp index de896775e40..3567e559a6a 100644 --- a/lldb/examples/darwin/heap_find/heap/heap_find.cpp +++ b/lldb/examples/darwin/heap_find/heap/heap_find.cpp @@ -13,39 +13,41 @@ // // (lldb) process load /path/to/libheap.dylib // -// Now you can use the "find_pointer_in_heap" and "find_cstring_in_heap" +// Now you can use the "find_pointer_in_heap" and "find_cstring_in_heap" // functions in the expression parser. // -// This will grep everything in all active allocation blocks and print and +// This will grep everything in all active allocation blocks and print and // malloc blocks that contain the pointer 0x112233000000: // // (lldb) expression find_pointer_in_heap (0x112233000000) // -// This will grep everything in all active allocation blocks and print and +// This will grep everything in all active allocation blocks and print and // malloc blocks that contain the C string "hello" (as a substring, no // NULL termination included): // // (lldb) expression find_cstring_in_heap ("hello") // -// The results will be printed to the STDOUT of the inferior program. The -// return value of the "find_pointer_in_heap" function is the number of +// The results will be printed to the STDOUT of the inferior program. The +// return value of the "find_pointer_in_heap" function is the number of // pointer references that were found. A quick example shows // // (lldb) expr find_pointer_in_heap(0x0000000104000410) // (uint32_t) $5 = 0x00000002 -// 0x104000740: 0x0000000104000410 found in malloc block 0x104000730 + 16 (malloc_size = 48) -// 0x100820060: 0x0000000104000410 found in malloc block 0x100820000 + 96 (malloc_size = 4096) +// 0x104000740: 0x0000000104000410 found in malloc block 0x104000730 + 16 +// (malloc_size = 48) +// 0x100820060: 0x0000000104000410 found in malloc block 0x100820000 + 96 +// (malloc_size = 4096) // // From the above output we see that 0x104000410 was found in the malloc block // at 0x104000730 and 0x100820000. If we want to see what these blocks are, we -// can display the memory for this block using the "address" ("A" for short) +// can display the memory for this block using the "address" ("A" for short) // format. The address format shows pointers, and if those pointers point to // objects that have symbols or know data contents, it will display information // about the pointers: // -// (lldb) memory read --format address --count 1 0x104000730 +// (lldb) memory read --format address --count 1 0x104000730 // 0x104000730: 0x0000000100002460 (void *)0x0000000100002488: MyString -// +// // We can see that the first block is a "MyString" object that contains our // pointer value at offset 16. // @@ -53,9 +55,9 @@ // (lldb) memory read -fA 0x100820000 -c1 // 0x100820000: 0x4f545541a1a1a1a1 // (lldb) memory read 0x100820000 -// 0x100820000: a1 a1 a1 a1 41 55 54 4f 52 45 4c 45 41 53 45 21 ....AUTORELEASE! -// 0x100820010: 78 00 82 00 01 00 00 00 60 f9 e8 75 ff 7f 00 00 x.......`..u.... -// +// 0x100820000: a1 a1 a1 a1 41 55 54 4f 52 45 4c 45 41 53 45 21 ....AUTORELEASE! +// 0x100820010: 78 00 82 00 01 00 00 00 60 f9 e8 75 ff 7f 00 00 x.......`..u.... +// // This is an objective C auto release pool object that contains our pointer. // C++ classes will show up if they are virtual as something like: // (lldb) memory read --format address --count 1 0x104008000 @@ -82,66 +84,47 @@ // Redefine private types from "/usr/local/include/stack_logging.h" //---------------------------------------------------------------------- typedef struct { - uint32_t type_flags; - uint64_t stack_identifier; - uint64_t argument; - mach_vm_address_t address; + uint32_t type_flags; + uint64_t stack_identifier; + uint64_t argument; + mach_vm_address_t address; } mach_stack_logging_record_t; //---------------------------------------------------------------------- // Redefine private defines from "/usr/local/include/stack_logging.h" //---------------------------------------------------------------------- -#define stack_logging_type_free 0 -#define stack_logging_type_generic 1 -#define stack_logging_type_alloc 2 -#define stack_logging_type_dealloc 4 +#define stack_logging_type_free 0 +#define stack_logging_type_generic 1 +#define stack_logging_type_alloc 2 +#define stack_logging_type_dealloc 4 // This bit is made up by this code -#define stack_logging_type_vm_region 8 +#define stack_logging_type_vm_region 8 //---------------------------------------------------------------------- -// Redefine private function prototypes from +// Redefine private function prototypes from // "/usr/local/include/stack_logging.h" //---------------------------------------------------------------------- -extern "C" kern_return_t -__mach_stack_logging_set_file_path ( - task_t task, - char* file_path -); - -extern "C" kern_return_t -__mach_stack_logging_get_frames ( - task_t task, - mach_vm_address_t address, - mach_vm_address_t *stack_frames_buffer, - uint32_t max_stack_frames, - uint32_t *count -); +extern "C" kern_return_t __mach_stack_logging_set_file_path(task_t task, + char *file_path); extern "C" kern_return_t -__mach_stack_logging_enumerate_records ( - task_t task, - mach_vm_address_t address, - void enumerator(mach_stack_logging_record_t, void *), - void *context -); +__mach_stack_logging_get_frames(task_t task, mach_vm_address_t address, + mach_vm_address_t *stack_frames_buffer, + uint32_t max_stack_frames, uint32_t *count); -extern "C" kern_return_t -__mach_stack_logging_frames_for_uniqued_stack ( - task_t task, - uint64_t stack_identifier, - mach_vm_address_t *stack_frames_buffer, - uint32_t max_stack_frames, - uint32_t *count -); +extern "C" kern_return_t __mach_stack_logging_enumerate_records( + task_t task, mach_vm_address_t address, + void enumerator(mach_stack_logging_record_t, void *), void *context); -extern "C" void *gdb_class_getClass (void *objc_class); +extern "C" kern_return_t __mach_stack_logging_frames_for_uniqued_stack( + task_t task, uint64_t stack_identifier, + mach_vm_address_t *stack_frames_buffer, uint32_t max_stack_frames, + uint32_t *count); -static void -range_info_callback (task_t task, - void *baton, - unsigned type, - uint64_t ptr_addr, - uint64_t ptr_size); +extern "C" void *gdb_class_getClass(void *objc_class); + +static void range_info_callback(task_t task, void *baton, unsigned type, + uint64_t ptr_addr, uint64_t ptr_size); //---------------------------------------------------------------------- // Redefine private global variables prototypes from @@ -158,289 +141,221 @@ extern "C" int stack_logging_enable_logging; //---------------------------------------------------------------------- // Local Typedefs and Types //---------------------------------------------------------------------- -typedef void range_callback_t (task_t task, void *baton, unsigned type, uint64_t ptr_addr, uint64_t ptr_size); -typedef void zone_callback_t (void *info, const malloc_zone_t *zone); +typedef void range_callback_t(task_t task, void *baton, unsigned type, + uint64_t ptr_addr, uint64_t ptr_size); +typedef void zone_callback_t(void *info, const malloc_zone_t *zone); typedef int (*comare_function_t)(const void *, const void *); -struct range_callback_info_t -{ - zone_callback_t *zone_callback; - range_callback_t *range_callback; - void *baton; - int check_vm_regions; +struct range_callback_info_t { + zone_callback_t *zone_callback; + range_callback_t *range_callback; + void *baton; + int check_vm_regions; }; -enum data_type_t -{ - eDataTypeAddress, - eDataTypeContainsData, - eDataTypeObjC, - eDataTypeHeapInfo +enum data_type_t { + eDataTypeAddress, + eDataTypeContainsData, + eDataTypeObjC, + eDataTypeHeapInfo }; -struct aligned_data_t -{ - const uint8_t *buffer; - uint32_t size; - uint32_t align; +struct aligned_data_t { + const uint8_t *buffer; + uint32_t size; + uint32_t align; }; -struct objc_data_t -{ - void *match_isa; // Set to NULL for all objective C objects - bool match_superclasses; +struct objc_data_t { + void *match_isa; // Set to NULL for all objective C objects + bool match_superclasses; }; -struct range_contains_data_callback_info_t -{ - data_type_t type; - const void *lookup_addr; - union - { - uintptr_t addr; - aligned_data_t data; - objc_data_t objc; - }; - uint32_t match_count; - bool done; - bool unique; +struct range_contains_data_callback_info_t { + data_type_t type; + const void *lookup_addr; + union { + uintptr_t addr; + aligned_data_t data; + objc_data_t objc; + }; + uint32_t match_count; + bool done; + bool unique; }; -struct malloc_match -{ - void *addr; - intptr_t size; - intptr_t offset; - uintptr_t type; +struct malloc_match { + void *addr; + intptr_t size; + intptr_t offset; + uintptr_t type; }; -struct malloc_stack_entry -{ - const void *address; - uint64_t argument; - uint32_t type_flags; - uint32_t num_frames; - mach_vm_address_t frames[MAX_FRAMES]; +struct malloc_stack_entry { + const void *address; + uint64_t argument; + uint32_t type_flags; + uint32_t num_frames; + mach_vm_address_t frames[MAX_FRAMES]; }; -struct malloc_block_contents -{ - union { - Class isa; - void *pointers[2]; - }; +struct malloc_block_contents { + union { + Class isa; + void *pointers[2]; + }; }; -static int -compare_void_ptr (const void *a, const void *b) -{ - Class a_ptr = *(Class *)a; - Class b_ptr = *(Class *)b; - if (a_ptr < b_ptr) return -1; - if (a_ptr > b_ptr) return +1; - return 0; +static int compare_void_ptr(const void *a, const void *b) { + Class a_ptr = *(Class *)a; + Class b_ptr = *(Class *)b; + if (a_ptr < b_ptr) + return -1; + if (a_ptr > b_ptr) + return +1; + return 0; } -class MatchResults -{ - enum { - k_max_entries = 8 * 1024 - }; -public: - MatchResults () : - m_size(0) - { - } - - void - clear() - { - m_size = 0; - bzero (&m_entries, sizeof(m_entries)); - } - - bool - empty() const - { - return m_size == 0; - } - - void - push_back (const malloc_match& m, bool unique = false) - { - if (unique) - { - // Don't add the entry if there is already a match for this address - for (uint32_t i=0; i<m_size; ++i) - { - if (((uint8_t *)m_entries[i].addr + m_entries[i].offset) == ((uint8_t *)m.addr + m.offset)) - return; // Duplicate entry - } - } - if (m_size < k_max_entries - 1) - { - m_entries[m_size] = m; - m_size++; - } - } +class MatchResults { + enum { k_max_entries = 8 * 1024 }; - malloc_match * - data () - { - // If empty, return NULL - if (empty()) - return NULL; - // In not empty, terminate and return the result - malloc_match terminator_entry = { NULL, 0, 0, 0 }; - // We always leave room for an empty entry at the end - m_entries[m_size] = terminator_entry; - return m_entries; - } +public: + MatchResults() : m_size(0) {} + + void clear() { + m_size = 0; + bzero(&m_entries, sizeof(m_entries)); + } + + bool empty() const { return m_size == 0; } + + void push_back(const malloc_match &m, bool unique = false) { + if (unique) { + // Don't add the entry if there is already a match for this address + for (uint32_t i = 0; i < m_size; ++i) { + if (((uint8_t *)m_entries[i].addr + m_entries[i].offset) == + ((uint8_t *)m.addr + m.offset)) + return; // Duplicate entry + } + } + if (m_size < k_max_entries - 1) { + m_entries[m_size] = m; + m_size++; + } + } + + malloc_match *data() { + // If empty, return NULL + if (empty()) + return NULL; + // In not empty, terminate and return the result + malloc_match terminator_entry = {NULL, 0, 0, 0}; + // We always leave room for an empty entry at the end + m_entries[m_size] = terminator_entry; + return m_entries; + } protected: - malloc_match m_entries[k_max_entries]; - uint32_t m_size; + malloc_match m_entries[k_max_entries]; + uint32_t m_size; }; -class MallocStackLoggingEntries -{ - enum { k_max_entries = 128 }; -public: - MallocStackLoggingEntries () : - m_size(0) - { - } +class MallocStackLoggingEntries { + enum { k_max_entries = 128 }; - void - clear() - { - m_size = 0; - } +public: + MallocStackLoggingEntries() : m_size(0) {} - bool - empty() const - { - return m_size == 0; - } + void clear() { m_size = 0; } + bool empty() const { return m_size == 0; } - malloc_stack_entry * - next () - { - if (m_size < k_max_entries - 1) - { - malloc_stack_entry * result = m_entries + m_size; - ++m_size; - return result; - } - return NULL; // Out of entries... + malloc_stack_entry *next() { + if (m_size < k_max_entries - 1) { + malloc_stack_entry *result = m_entries + m_size; + ++m_size; + return result; } + return NULL; // Out of entries... + } - malloc_stack_entry * - data () - { - // If empty, return NULL - if (empty()) - return NULL; - // In not empty, terminate and return the result - m_entries[m_size].address = NULL; - m_entries[m_size].argument = 0; - m_entries[m_size].type_flags = 0; - m_entries[m_size].num_frames = 0; - return m_entries; - } + malloc_stack_entry *data() { + // If empty, return NULL + if (empty()) + return NULL; + // In not empty, terminate and return the result + m_entries[m_size].address = NULL; + m_entries[m_size].argument = 0; + m_entries[m_size].type_flags = 0; + m_entries[m_size].num_frames = 0; + return m_entries; + } -protected: - malloc_stack_entry m_entries[k_max_entries]; - uint32_t m_size; +protected: + malloc_stack_entry m_entries[k_max_entries]; + uint32_t m_size; }; //---------------------------------------------------------------------- // A safe way to allocate memory and keep it from interfering with the // malloc enumerators. //---------------------------------------------------------------------- -void * -safe_malloc(size_t n_bytes) -{ - if (n_bytes > 0) - { - const int k_page_size = getpagesize(); - const mach_vm_size_t vm_size = ((n_bytes + k_page_size - 1)/k_page_size) * k_page_size; - vm_address_t address = 0; - kern_return_t kerr = vm_allocate (mach_task_self(), &address, vm_size, true); - if (kerr == KERN_SUCCESS) - return (void *)address; - } - return NULL; +void *safe_malloc(size_t n_bytes) { + if (n_bytes > 0) { + const int k_page_size = getpagesize(); + const mach_vm_size_t vm_size = + ((n_bytes + k_page_size - 1) / k_page_size) * k_page_size; + vm_address_t address = 0; + kern_return_t kerr = vm_allocate(mach_task_self(), &address, vm_size, true); + if (kerr == KERN_SUCCESS) + return (void *)address; + } + return NULL; } - //---------------------------------------------------------------------- // ObjCClasses //---------------------------------------------------------------------- -class ObjCClasses -{ +class ObjCClasses { public: - ObjCClasses() : - m_objc_class_ptrs (NULL), - m_size (0) - { + ObjCClasses() : m_objc_class_ptrs(NULL), m_size(0) {} + + bool Update() { + // TODO: find out if class list has changed and update if needed + if (m_objc_class_ptrs == NULL) { + m_size = objc_getClassList(NULL, 0); + if (m_size > 0) { + // Allocate the class pointers + m_objc_class_ptrs = (Class *)safe_malloc(m_size * sizeof(Class)); + m_size = objc_getClassList(m_objc_class_ptrs, m_size); + // Sort Class pointers for quick lookup + ::qsort(m_objc_class_ptrs, m_size, sizeof(Class), compare_void_ptr); + } else + return false; } + return true; + } - bool - Update() - { - // TODO: find out if class list has changed and update if needed - if (m_objc_class_ptrs == NULL) - { - m_size = objc_getClassList(NULL, 0); - if (m_size > 0) - { - // Allocate the class pointers - m_objc_class_ptrs = (Class *)safe_malloc (m_size * sizeof(Class)); - m_size = objc_getClassList(m_objc_class_ptrs, m_size); - // Sort Class pointers for quick lookup - ::qsort (m_objc_class_ptrs, m_size, sizeof(Class), compare_void_ptr); - } - else - return false; - } - return true; - } - - uint32_t - FindClassIndex (Class isa) - { - Class *matching_class = (Class *)bsearch (&isa, - m_objc_class_ptrs, - m_size, - sizeof(Class), - compare_void_ptr); - if (matching_class) - { - uint32_t idx = matching_class - m_objc_class_ptrs; - return idx; - } - return UINT32_MAX; - } - - Class - GetClassAtIndex (uint32_t idx) const - { - if (idx < m_size) - return m_objc_class_ptrs[idx]; - return NULL; - } - uint32_t - GetSize() const - { - return m_size; + uint32_t FindClassIndex(Class isa) { + Class *matching_class = (Class *)bsearch(&isa, m_objc_class_ptrs, m_size, + sizeof(Class), compare_void_ptr); + if (matching_class) { + uint32_t idx = matching_class - m_objc_class_ptrs; + return idx; } -private: - Class *m_objc_class_ptrs; - uint32_t m_size; -}; + return UINT32_MAX; + } + Class GetClassAtIndex(uint32_t idx) const { + if (idx < m_size) + return m_objc_class_ptrs[idx]; + return NULL; + } + uint32_t GetSize() const { return m_size; } +private: + Class *m_objc_class_ptrs; + uint32_t m_size; +}; //---------------------------------------------------------------------- // Local global variables @@ -453,127 +368,104 @@ ObjCClasses g_objc_classes; // ObjCClassInfo //---------------------------------------------------------------------- -enum HeapInfoSortType -{ - eSortTypeNone, - eSortTypeBytes, - eSortTypeCount -}; +enum HeapInfoSortType { eSortTypeNone, eSortTypeBytes, eSortTypeCount }; -class ObjCClassInfo -{ +class ObjCClassInfo { public: - ObjCClassInfo() : - m_entries (NULL), - m_size (0), - m_sort_type (eSortTypeNone) - { - } - - void - Update (const ObjCClasses &objc_classes) - { - m_size = objc_classes.GetSize(); - m_entries = (Entry *)safe_malloc (m_size * sizeof(Entry)); - m_sort_type = eSortTypeNone; - Reset (); - } - - bool - AddInstance (uint32_t idx, uint64_t ptr_size) - { - if (m_size == 0) - Update (g_objc_classes); - // Update the totals for the classes - if (idx < m_size) - { - m_entries[idx].bytes += ptr_size; - ++m_entries[idx].count; - return true; - } - return false; - } - - void - Reset () - { - m_sort_type = eSortTypeNone; - for (uint32_t i=0; i<m_size; ++i) - { - // In case we sort the entries after gathering the data, we will - // want to know the index into the m_objc_class_ptrs[] array. - m_entries[i].idx = i; - m_entries[i].bytes = 0; - m_entries[i].count = 0; - } - } - void - SortByTotalBytes (const ObjCClasses &objc_classes, bool print) - { - if (m_sort_type != eSortTypeBytes && m_size > 0) - { - ::qsort (m_entries, m_size, sizeof(Entry), (comare_function_t)compare_bytes); - m_sort_type = eSortTypeBytes; - } - if (print && m_size > 0) - { - puts("Objective C objects by total bytes:"); - puts("Total Bytes Class Name"); - puts("----------- -----------------------------------------------------------------"); - for (uint32_t i=0; i<m_size && m_entries[i].bytes > 0; ++i) - { - printf ("%11llu %s\n", m_entries[i].bytes, class_getName (objc_classes.GetClassAtIndex(m_entries[i].idx))); - } - } - } - void - SortByTotalCount (const ObjCClasses &objc_classes, bool print) - { - if (m_sort_type != eSortTypeCount && m_size > 0) - { - ::qsort (m_entries, m_size, sizeof(Entry), (comare_function_t)compare_count); - m_sort_type = eSortTypeCount; - } - if (print && m_size > 0) - { - puts("Objective C objects by total count:"); - puts("Count Class Name"); - puts("-------- -----------------------------------------------------------------"); - for (uint32_t i=0; i<m_size && m_entries[i].count > 0; ++i) - { - printf ("%8u %s\n", m_entries[i].count, class_getName (objc_classes.GetClassAtIndex(m_entries[i].idx))); - } - } - } -private: - struct Entry - { - uint32_t idx; // Index into the m_objc_class_ptrs[] array - uint32_t count; // Number of object instances that were found - uint64_t bytes; // Total number of bytes for each objc class - }; - - static int - compare_bytes (const Entry *a, const Entry *b) - { - // Reverse the comparison to most bytes entries end up at top of list - if (a->bytes > b->bytes) return -1; - if (a->bytes < b->bytes) return +1; - return 0; - } + ObjCClassInfo() : m_entries(NULL), m_size(0), m_sort_type(eSortTypeNone) {} + + void Update(const ObjCClasses &objc_classes) { + m_size = objc_classes.GetSize(); + m_entries = (Entry *)safe_malloc(m_size * sizeof(Entry)); + m_sort_type = eSortTypeNone; + Reset(); + } + + bool AddInstance(uint32_t idx, uint64_t ptr_size) { + if (m_size == 0) + Update(g_objc_classes); + // Update the totals for the classes + if (idx < m_size) { + m_entries[idx].bytes += ptr_size; + ++m_entries[idx].count; + return true; + } + return false; + } + + void Reset() { + m_sort_type = eSortTypeNone; + for (uint32_t i = 0; i < m_size; ++i) { + // In case we sort the entries after gathering the data, we will + // want to know the index into the m_objc_class_ptrs[] array. + m_entries[i].idx = i; + m_entries[i].bytes = 0; + m_entries[i].count = 0; + } + } + void SortByTotalBytes(const ObjCClasses &objc_classes, bool print) { + if (m_sort_type != eSortTypeBytes && m_size > 0) { + ::qsort(m_entries, m_size, sizeof(Entry), + (comare_function_t)compare_bytes); + m_sort_type = eSortTypeBytes; + } + if (print && m_size > 0) { + puts("Objective C objects by total bytes:"); + puts("Total Bytes Class Name"); + puts("----------- " + "-----------------------------------------------------------------"); + for (uint32_t i = 0; i < m_size && m_entries[i].bytes > 0; ++i) { + printf("%11llu %s\n", m_entries[i].bytes, + class_getName(objc_classes.GetClassAtIndex(m_entries[i].idx))); + } + } + } + void SortByTotalCount(const ObjCClasses &objc_classes, bool print) { + if (m_sort_type != eSortTypeCount && m_size > 0) { + ::qsort(m_entries, m_size, sizeof(Entry), + (comare_function_t)compare_count); + m_sort_type = eSortTypeCount; + } + if (print && m_size > 0) { + puts("Objective C objects by total count:"); + puts("Count Class Name"); + puts("-------- " + "-----------------------------------------------------------------"); + for (uint32_t i = 0; i < m_size && m_entries[i].count > 0; ++i) { + printf("%8u %s\n", m_entries[i].count, + class_getName(objc_classes.GetClassAtIndex(m_entries[i].idx))); + } + } + } - static int - compare_count (const Entry *a, const Entry *b) - { - // Reverse the comparison to most count entries end up at top of list - if (a->count > b->count) return -1; - if (a->count < b->count) return +1; - return 0; - } +private: + struct Entry { + uint32_t idx; // Index into the m_objc_class_ptrs[] array + uint32_t count; // Number of object instances that were found + uint64_t bytes; // Total number of bytes for each objc class + }; + + static int compare_bytes(const Entry *a, const Entry *b) { + // Reverse the comparison to most bytes entries end up at top of list + if (a->bytes > b->bytes) + return -1; + if (a->bytes < b->bytes) + return +1; + return 0; + } + + static int compare_count(const Entry *a, const Entry *b) { + // Reverse the comparison to most count entries end up at top of list + if (a->count > b->count) + return -1; + if (a->count < b->count) + return +1; + return 0; + } - Entry *m_entries; - uint32_t m_size; - HeapInfoSortType m_sort_type; + Entry *m_entries; + uint32_t m_size; + HeapInfoSortType m_sort_type; }; ObjCClassInfo g_objc_class_snapshot; @@ -585,74 +477,62 @@ ObjCClassInfo g_objc_class_snapshot; // by the code that iterates through all of the malloc blocks to read // the memory in this process. //---------------------------------------------------------------------- -static kern_return_t -task_peek (task_t task, vm_address_t remote_address, vm_size_t size, void **local_memory) -{ - *local_memory = (void*) remote_address; - return KERN_SUCCESS; +static kern_return_t task_peek(task_t task, vm_address_t remote_address, + vm_size_t size, void **local_memory) { + *local_memory = (void *)remote_address; + return KERN_SUCCESS; } +static const void foreach_zone_in_this_process(range_callback_info_t *info) { + if (info == NULL || info->zone_callback == NULL) + return; -static const void -foreach_zone_in_this_process (range_callback_info_t *info) -{ - if (info == NULL || info->zone_callback == NULL) - return; + vm_address_t *zones = NULL; + unsigned int num_zones = 0; - vm_address_t *zones = NULL; - unsigned int num_zones = 0; - - kern_return_t err = malloc_get_all_zones (0, task_peek, &zones, &num_zones); - if (KERN_SUCCESS == err) - { - for (unsigned int i=0; i<num_zones; ++i) - { - info->zone_callback (info, (const malloc_zone_t *)zones[i]); - } + kern_return_t err = malloc_get_all_zones(0, task_peek, &zones, &num_zones); + if (KERN_SUCCESS == err) { + for (unsigned int i = 0; i < num_zones; ++i) { + info->zone_callback(info, (const malloc_zone_t *)zones[i]); } - - if (info->check_vm_regions) - { -#if defined (VM_REGION_SUBMAP_SHORT_INFO_COUNT_64) - typedef vm_region_submap_short_info_data_64_t RegionInfo; - enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 }; + } + + if (info->check_vm_regions) { +#if defined(VM_REGION_SUBMAP_SHORT_INFO_COUNT_64) + typedef vm_region_submap_short_info_data_64_t RegionInfo; + enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 }; #else - typedef vm_region_submap_info_data_64_t RegionInfo; - enum { kRegionInfoSize = VM_REGION_SUBMAP_INFO_COUNT_64 }; + typedef vm_region_submap_info_data_64_t RegionInfo; + enum { kRegionInfoSize = VM_REGION_SUBMAP_INFO_COUNT_64 }; #endif - task_t task = mach_task_self(); - mach_vm_address_t vm_region_base_addr; - mach_vm_size_t vm_region_size; - natural_t vm_region_depth; - RegionInfo vm_region_info; - - ((range_contains_data_callback_info_t *)info->baton)->unique = true; - - for (vm_region_base_addr = 0, vm_region_size = 1; vm_region_size != 0; vm_region_base_addr += vm_region_size) - { - mach_msg_type_number_t vm_region_info_size = kRegionInfoSize; - const kern_return_t err = mach_vm_region_recurse (task, - &vm_region_base_addr, - &vm_region_size, - &vm_region_depth, - (vm_region_recurse_info_t)&vm_region_info, - &vm_region_info_size); - if (err) - break; - // Check all read + write regions. This will cover the thread stacks - // and any regions of memory that aren't covered by the heap - if (vm_region_info.protection & VM_PROT_WRITE && - vm_region_info.protection & VM_PROT_READ) - { - //printf ("checking vm_region: [0x%16.16llx - 0x%16.16llx)\n", (uint64_t)vm_region_base_addr, (uint64_t)vm_region_base_addr + vm_region_size); - range_info_callback (task, - info->baton, - stack_logging_type_vm_region, - vm_region_base_addr, - vm_region_size); - } - } - } + task_t task = mach_task_self(); + mach_vm_address_t vm_region_base_addr; + mach_vm_size_t vm_region_size; + natural_t vm_region_depth; + RegionInfo vm_region_info; + + ((range_contains_data_callback_info_t *)info->baton)->unique = true; + + for (vm_region_base_addr = 0, vm_region_size = 1; vm_region_size != 0; + vm_region_base_addr += vm_region_size) { + mach_msg_type_number_t vm_region_info_size = kRegionInfoSize; + const kern_return_t err = mach_vm_region_recurse( + task, &vm_region_base_addr, &vm_region_size, &vm_region_depth, + (vm_region_recurse_info_t)&vm_region_info, &vm_region_info_size); + if (err) + break; + // Check all read + write regions. This will cover the thread stacks + // and any regions of memory that aren't covered by the heap + if (vm_region_info.protection & VM_PROT_WRITE && + vm_region_info.protection & VM_PROT_READ) { + // printf ("checking vm_region: [0x%16.16llx - 0x%16.16llx)\n", + // (uint64_t)vm_region_base_addr, (uint64_t)vm_region_base_addr + + // vm_region_size); + range_info_callback(task, info->baton, stack_logging_type_vm_region, + vm_region_base_addr, vm_region_size); + } + } + } } //---------------------------------------------------------------------- @@ -661,235 +541,203 @@ foreach_zone_in_this_process (range_callback_info_t *info) // A simple callback that will dump each malloc block and all available // info from the enumeration callback perspective. //---------------------------------------------------------------------- -static void -dump_malloc_block_callback (task_t task, void *baton, unsigned type, uint64_t ptr_addr, uint64_t ptr_size) -{ - printf ("task = 0x%4.4x: baton = %p, type = %u, ptr_addr = 0x%llx + 0x%llu\n", task, baton, type, ptr_addr, ptr_size); +static void dump_malloc_block_callback(task_t task, void *baton, unsigned type, + uint64_t ptr_addr, uint64_t ptr_size) { + printf("task = 0x%4.4x: baton = %p, type = %u, ptr_addr = 0x%llx + 0x%llu\n", + task, baton, type, ptr_addr, ptr_size); } -static void -ranges_callback (task_t task, void *baton, unsigned type, vm_range_t *ptrs, unsigned count) -{ - range_callback_info_t *info = (range_callback_info_t *)baton; - while(count--) { - info->range_callback (task, info->baton, type, ptrs->address, ptrs->size); - ptrs++; - } +static void ranges_callback(task_t task, void *baton, unsigned type, + vm_range_t *ptrs, unsigned count) { + range_callback_info_t *info = (range_callback_info_t *)baton; + while (count--) { + info->range_callback(task, info->baton, type, ptrs->address, ptrs->size); + ptrs++; + } } -static void -enumerate_range_in_zone (void *baton, const malloc_zone_t *zone) -{ - range_callback_info_t *info = (range_callback_info_t *)baton; - - if (zone && zone->introspect) - zone->introspect->enumerator (mach_task_self(), - info, - MALLOC_PTR_IN_USE_RANGE_TYPE, - (vm_address_t)zone, - task_peek, - ranges_callback); +static void enumerate_range_in_zone(void *baton, const malloc_zone_t *zone) { + range_callback_info_t *info = (range_callback_info_t *)baton; + + if (zone && zone->introspect) + zone->introspect->enumerator( + mach_task_self(), info, MALLOC_PTR_IN_USE_RANGE_TYPE, + (vm_address_t)zone, task_peek, ranges_callback); } -static void -range_info_callback (task_t task, void *baton, unsigned type, uint64_t ptr_addr, uint64_t ptr_size) -{ - const uint64_t end_addr = ptr_addr + ptr_size; - - range_contains_data_callback_info_t *info = (range_contains_data_callback_info_t *)baton; - switch (info->type) - { - case eDataTypeAddress: - // Check if the current malloc block contains an address specified by "info->addr" - if (ptr_addr <= info->addr && info->addr < end_addr) - { - ++info->match_count; - malloc_match match = { (void *)ptr_addr, ptr_size, info->addr - ptr_addr, type }; - g_matches.push_back(match, info->unique); - } - break; - - case eDataTypeContainsData: - // Check if the current malloc block contains data specified in "info->data" - { - const uint32_t size = info->data.size; - if (size < ptr_size) // Make sure this block can contain this data - { - uint8_t *ptr_data = NULL; - if (task_peek (task, ptr_addr, ptr_size, (void **)&ptr_data) == KERN_SUCCESS) - { - const void *buffer = info->data.buffer; - assert (ptr_data); - const uint32_t align = info->data.align; - for (uint64_t addr = ptr_addr; - addr < end_addr && ((end_addr - addr) >= size); - addr += align, ptr_data += align) - { - if (memcmp (buffer, ptr_data, size) == 0) - { - ++info->match_count; - malloc_match match = { (void *)ptr_addr, ptr_size, addr - ptr_addr, type }; - g_matches.push_back(match, info->unique); - } - } - } - else - { - printf ("0x%llx: error: couldn't read %llu bytes\n", ptr_addr, ptr_size); - } +static void range_info_callback(task_t task, void *baton, unsigned type, + uint64_t ptr_addr, uint64_t ptr_size) { + const uint64_t end_addr = ptr_addr + ptr_size; + + range_contains_data_callback_info_t *info = + (range_contains_data_callback_info_t *)baton; + switch (info->type) { + case eDataTypeAddress: + // Check if the current malloc block contains an address specified by + // "info->addr" + if (ptr_addr <= info->addr && info->addr < end_addr) { + ++info->match_count; + malloc_match match = {(void *)ptr_addr, ptr_size, info->addr - ptr_addr, + type}; + g_matches.push_back(match, info->unique); + } + break; + + case eDataTypeContainsData: + // Check if the current malloc block contains data specified in "info->data" + { + const uint32_t size = info->data.size; + if (size < ptr_size) // Make sure this block can contain this data + { + uint8_t *ptr_data = NULL; + if (task_peek(task, ptr_addr, ptr_size, (void **)&ptr_data) == + KERN_SUCCESS) { + const void *buffer = info->data.buffer; + assert(ptr_data); + const uint32_t align = info->data.align; + for (uint64_t addr = ptr_addr; + addr < end_addr && ((end_addr - addr) >= size); + addr += align, ptr_data += align) { + if (memcmp(buffer, ptr_data, size) == 0) { + ++info->match_count; + malloc_match match = {(void *)ptr_addr, ptr_size, addr - ptr_addr, + type}; + g_matches.push_back(match, info->unique); } + } + } else { + printf("0x%llx: error: couldn't read %llu bytes\n", ptr_addr, + ptr_size); } - break; - - case eDataTypeObjC: - // Check if the current malloc block contains an objective C object - // of any sort where the first pointer in the object is an OBJC class - // pointer (an isa) - { - malloc_block_contents *block_contents = NULL; - if (task_peek (task, ptr_addr, sizeof(void *), (void **)&block_contents) == KERN_SUCCESS) - { - // We assume that g_objc_classes is up to date - // that the class list was verified to have some classes in it - // before calling this function - const uint32_t objc_class_idx = g_objc_classes.FindClassIndex (block_contents->isa); - if (objc_class_idx != UINT32_MAX) - { - bool match = false; - if (info->objc.match_isa == 0) - { - // Match any objective C object - match = true; - } - else - { - // Only match exact isa values in the current class or - // optionally in the super classes - if (info->objc.match_isa == block_contents->isa) - match = true; - else if (info->objc.match_superclasses) - { - Class super = class_getSuperclass(block_contents->isa); - while (super) - { - match = super == info->objc.match_isa; - if (match) - break; - super = class_getSuperclass(super); - } - } - } - if (match) - { - //printf (" success\n"); - ++info->match_count; - malloc_match match = { (void *)ptr_addr, ptr_size, 0, type }; - g_matches.push_back(match, info->unique); - } - else - { - //printf (" error: wrong class: %s\n", dl_info.dli_sname); - } - } - else - { - //printf ("\terror: symbol not objc class: %s\n", dl_info.dli_sname); - return; - } + } + } + break; + + case eDataTypeObjC: + // Check if the current malloc block contains an objective C object + // of any sort where the first pointer in the object is an OBJC class + // pointer (an isa) + { + malloc_block_contents *block_contents = NULL; + if (task_peek(task, ptr_addr, sizeof(void *), (void **)&block_contents) == + KERN_SUCCESS) { + // We assume that g_objc_classes is up to date + // that the class list was verified to have some classes in it + // before calling this function + const uint32_t objc_class_idx = + g_objc_classes.FindClassIndex(block_contents->isa); + if (objc_class_idx != UINT32_MAX) { + bool match = false; + if (info->objc.match_isa == 0) { + // Match any objective C object + match = true; + } else { + // Only match exact isa values in the current class or + // optionally in the super classes + if (info->objc.match_isa == block_contents->isa) + match = true; + else if (info->objc.match_superclasses) { + Class super = class_getSuperclass(block_contents->isa); + while (super) { + match = super == info->objc.match_isa; + if (match) + break; + super = class_getSuperclass(super); + } } + } + if (match) { + // printf (" success\n"); + ++info->match_count; + malloc_match match = {(void *)ptr_addr, ptr_size, 0, type}; + g_matches.push_back(match, info->unique); + } else { + // printf (" error: wrong class: %s\n", dl_info.dli_sname); + } + } else { + // printf ("\terror: symbol not objc class: %s\n", dl_info.dli_sname); + return; } - break; - - case eDataTypeHeapInfo: - // Check if the current malloc block contains an objective C object - // of any sort where the first pointer in the object is an OBJC class - // pointer (an isa) - { - malloc_block_contents *block_contents = NULL; - if (task_peek (task, ptr_addr, sizeof(void *), (void **)&block_contents) == KERN_SUCCESS) - { - // We assume that g_objc_classes is up to date - // that the class list was verified to have some classes in it - // before calling this function - const uint32_t objc_class_idx = g_objc_classes.FindClassIndex (block_contents->isa); - if (objc_class_idx != UINT32_MAX) - { - // This is an objective C object - g_objc_class_snapshot.AddInstance (objc_class_idx, ptr_size); - } - else - { - // Classify other heap info - } - } + } + } + break; + + case eDataTypeHeapInfo: + // Check if the current malloc block contains an objective C object + // of any sort where the first pointer in the object is an OBJC class + // pointer (an isa) + { + malloc_block_contents *block_contents = NULL; + if (task_peek(task, ptr_addr, sizeof(void *), (void **)&block_contents) == + KERN_SUCCESS) { + // We assume that g_objc_classes is up to date + // that the class list was verified to have some classes in it + // before calling this function + const uint32_t objc_class_idx = + g_objc_classes.FindClassIndex(block_contents->isa); + if (objc_class_idx != UINT32_MAX) { + // This is an objective C object + g_objc_class_snapshot.AddInstance(objc_class_idx, ptr_size); + } else { + // Classify other heap info } - break; - + } } + break; + } +} + +static void +get_stack_for_address_enumerator(mach_stack_logging_record_t stack_record, + void *task_ptr) { + malloc_stack_entry *stack_entry = g_malloc_stack_history.next(); + if (stack_entry) { + stack_entry->address = (void *)stack_record.address; + stack_entry->type_flags = stack_record.type_flags; + stack_entry->argument = stack_record.argument; + stack_entry->num_frames = 0; + stack_entry->frames[0] = 0; + kern_return_t err = __mach_stack_logging_frames_for_uniqued_stack( + *(task_t *)task_ptr, stack_record.stack_identifier, stack_entry->frames, + MAX_FRAMES, &stack_entry->num_frames); + // Terminate the frames with zero if there is room + if (stack_entry->num_frames < MAX_FRAMES) + stack_entry->frames[stack_entry->num_frames] = 0; + } } -static void -get_stack_for_address_enumerator(mach_stack_logging_record_t stack_record, void *task_ptr) -{ +malloc_stack_entry *get_stack_history_for_address(const void *addr, + int history) { + if (!stack_logging_enable_logging) + return NULL; + g_malloc_stack_history.clear(); + kern_return_t err; + task_t task = mach_task_self(); + if (history) { + err = __mach_stack_logging_enumerate_records( + task, (mach_vm_address_t)addr, get_stack_for_address_enumerator, &task); + } else { malloc_stack_entry *stack_entry = g_malloc_stack_history.next(); - if (stack_entry) - { - stack_entry->address = (void *)stack_record.address; - stack_entry->type_flags = stack_record.type_flags; - stack_entry->argument = stack_record.argument; - stack_entry->num_frames = 0; - stack_entry->frames[0] = 0; - kern_return_t err = __mach_stack_logging_frames_for_uniqued_stack (*(task_t *)task_ptr, - stack_record.stack_identifier, - stack_entry->frames, - MAX_FRAMES, - &stack_entry->num_frames); + if (stack_entry) { + stack_entry->address = addr; + stack_entry->type_flags = stack_logging_type_alloc; + stack_entry->argument = 0; + stack_entry->num_frames = 0; + stack_entry->frames[0] = 0; + err = __mach_stack_logging_get_frames(task, (mach_vm_address_t)addr, + stack_entry->frames, MAX_FRAMES, + &stack_entry->num_frames); + if (err == 0 && stack_entry->num_frames > 0) { // Terminate the frames with zero if there is room if (stack_entry->num_frames < MAX_FRAMES) - stack_entry->frames[stack_entry->num_frames] = 0; - } -} - -malloc_stack_entry * -get_stack_history_for_address (const void * addr, int history) -{ - if (!stack_logging_enable_logging) - return NULL; - g_malloc_stack_history.clear(); - kern_return_t err; - task_t task = mach_task_self(); - if (history) - { - err = __mach_stack_logging_enumerate_records (task, - (mach_vm_address_t)addr, - get_stack_for_address_enumerator, - &task); - } - else - { - malloc_stack_entry *stack_entry = g_malloc_stack_history.next(); - if (stack_entry) - { - stack_entry->address = addr; - stack_entry->type_flags = stack_logging_type_alloc; - stack_entry->argument = 0; - stack_entry->num_frames = 0; - stack_entry->frames[0] = 0; - err = __mach_stack_logging_get_frames(task, (mach_vm_address_t)addr, stack_entry->frames, MAX_FRAMES, &stack_entry->num_frames); - if (err == 0 && stack_entry->num_frames > 0) - { - // Terminate the frames with zero if there is room - if (stack_entry->num_frames < MAX_FRAMES) - stack_entry->frames[stack_entry->num_frames] = 0; - } - else - { - g_malloc_stack_history.clear(); - } - } - } - // Return data if there is any - return g_malloc_stack_history.data(); + stack_entry->frames[stack_entry->num_frames] = 0; + } else { + g_malloc_stack_history.clear(); + } + } + } + // Return data if there is any + return g_malloc_stack_history.data(); } //---------------------------------------------------------------------- @@ -898,28 +746,26 @@ get_stack_history_for_address (const void * addr, int history) // Finds a pointer value inside one or more currently valid malloc // blocks. //---------------------------------------------------------------------- -malloc_match * -find_pointer_in_heap (const void * addr, int check_vm_regions) -{ - g_matches.clear(); - // Setup "info" to look for a malloc block that contains data - // that is the pointer - if (addr) - { - range_contains_data_callback_info_t data_info; - data_info.type = eDataTypeContainsData; // Check each block for data - data_info.data.buffer = (uint8_t *)&addr; // What data? The pointer value passed in - data_info.data.size = sizeof(addr); // How many bytes? The byte size of a pointer - data_info.data.align = sizeof(addr); // Align to a pointer byte size - data_info.match_count = 0; // Initialize the match count to zero - data_info.done = false; // Set done to false so searching doesn't stop - data_info.unique = false; // Set to true when iterating on the vm_regions - range_callback_info_t info = { enumerate_range_in_zone, range_info_callback, &data_info, check_vm_regions }; - foreach_zone_in_this_process (&info); - - - } - return g_matches.data(); +malloc_match *find_pointer_in_heap(const void *addr, int check_vm_regions) { + g_matches.clear(); + // Setup "info" to look for a malloc block that contains data + // that is the pointer + if (addr) { + range_contains_data_callback_info_t data_info; + data_info.type = eDataTypeContainsData; // Check each block for data + data_info.data.buffer = + (uint8_t *)&addr; // What data? The pointer value passed in + data_info.data.size = + sizeof(addr); // How many bytes? The byte size of a pointer + data_info.data.align = sizeof(addr); // Align to a pointer byte size + data_info.match_count = 0; // Initialize the match count to zero + data_info.done = false; // Set done to false so searching doesn't stop + data_info.unique = false; // Set to true when iterating on the vm_regions + range_callback_info_t info = {enumerate_range_in_zone, range_info_callback, + &data_info, check_vm_regions}; + foreach_zone_in_this_process(&info); + } + return g_matches.data(); } //---------------------------------------------------------------------- @@ -928,95 +774,90 @@ find_pointer_in_heap (const void * addr, int check_vm_regions) // Finds a pointer value inside one or more currently valid malloc // blocks. //---------------------------------------------------------------------- -malloc_match * -find_pointer_in_memory (uint64_t memory_addr, uint64_t memory_size, const void * addr) -{ - g_matches.clear(); - // Setup "info" to look for a malloc block that contains data - // that is the pointer - range_contains_data_callback_info_t data_info; - data_info.type = eDataTypeContainsData; // Check each block for data - data_info.data.buffer = (uint8_t *)&addr; // What data? The pointer value passed in - data_info.data.size = sizeof(addr); // How many bytes? The byte size of a pointer - data_info.data.align = sizeof(addr); // Align to a pointer byte size - data_info.match_count = 0; // Initialize the match count to zero - data_info.done = false; // Set done to false so searching doesn't stop - data_info.unique = false; // Set to true when iterating on the vm_regions - range_info_callback (mach_task_self(), &data_info, stack_logging_type_generic, memory_addr, memory_size); - return g_matches.data(); +malloc_match *find_pointer_in_memory(uint64_t memory_addr, uint64_t memory_size, + const void *addr) { + g_matches.clear(); + // Setup "info" to look for a malloc block that contains data + // that is the pointer + range_contains_data_callback_info_t data_info; + data_info.type = eDataTypeContainsData; // Check each block for data + data_info.data.buffer = + (uint8_t *)&addr; // What data? The pointer value passed in + data_info.data.size = + sizeof(addr); // How many bytes? The byte size of a pointer + data_info.data.align = sizeof(addr); // Align to a pointer byte size + data_info.match_count = 0; // Initialize the match count to zero + data_info.done = false; // Set done to false so searching doesn't stop + data_info.unique = false; // Set to true when iterating on the vm_regions + range_info_callback(mach_task_self(), &data_info, stack_logging_type_generic, + memory_addr, memory_size); + return g_matches.data(); } //---------------------------------------------------------------------- // find_objc_objects_in_memory // // Find all instances of ObjC classes 'c', or all ObjC classes if 'c' is -// NULL. If 'c' is non NULL, then also check objects to see if they +// NULL. If 'c' is non NULL, then also check objects to see if they // inherit from 'c' //---------------------------------------------------------------------- -malloc_match * -find_objc_objects_in_memory (void *isa, int check_vm_regions) -{ - g_matches.clear(); - if (g_objc_classes.Update()) - { - // Setup "info" to look for a malloc block that contains data - // that is the pointer - range_contains_data_callback_info_t data_info; - data_info.type = eDataTypeObjC; // Check each block for data - data_info.objc.match_isa = isa; - data_info.objc.match_superclasses = true; - data_info.match_count = 0; // Initialize the match count to zero - data_info.done = false; // Set done to false so searching doesn't stop - data_info.unique = false; // Set to true when iterating on the vm_regions - range_callback_info_t info = { enumerate_range_in_zone, range_info_callback, &data_info, check_vm_regions }; - foreach_zone_in_this_process (&info); - } - return g_matches.data(); +malloc_match *find_objc_objects_in_memory(void *isa, int check_vm_regions) { + g_matches.clear(); + if (g_objc_classes.Update()) { + // Setup "info" to look for a malloc block that contains data + // that is the pointer + range_contains_data_callback_info_t data_info; + data_info.type = eDataTypeObjC; // Check each block for data + data_info.objc.match_isa = isa; + data_info.objc.match_superclasses = true; + data_info.match_count = 0; // Initialize the match count to zero + data_info.done = false; // Set done to false so searching doesn't stop + data_info.unique = false; // Set to true when iterating on the vm_regions + range_callback_info_t info = {enumerate_range_in_zone, range_info_callback, + &data_info, check_vm_regions}; + foreach_zone_in_this_process(&info); + } + return g_matches.data(); } //---------------------------------------------------------------------- // get_heap_info // -// Gather information for all allocations on the heap and report +// Gather information for all allocations on the heap and report // statistics. //---------------------------------------------------------------------- -void -get_heap_info (int sort_type) -{ - if (g_objc_classes.Update()) - { - // Reset all stats - g_objc_class_snapshot.Reset (); - // Setup "info" to look for a malloc block that contains data - // that is the pointer - range_contains_data_callback_info_t data_info; - data_info.type = eDataTypeHeapInfo; // Check each block for data - data_info.match_count = 0; // Initialize the match count to zero - data_info.done = false; // Set done to false so searching doesn't stop - data_info.unique = false; // Set to true when iterating on the vm_regions - const int check_vm_regions = false; - range_callback_info_t info = { enumerate_range_in_zone, range_info_callback, &data_info, check_vm_regions }; - foreach_zone_in_this_process (&info); - - // Sort and print byte total bytes - switch (sort_type) - { - case eSortTypeNone: - default: - case eSortTypeBytes: - g_objc_class_snapshot.SortByTotalBytes(g_objc_classes, true); - break; - - case eSortTypeCount: - g_objc_class_snapshot.SortByTotalCount(g_objc_classes, true); - break; - } - } - else - { - printf ("error: no objective C classes\n"); - } +void get_heap_info(int sort_type) { + if (g_objc_classes.Update()) { + // Reset all stats + g_objc_class_snapshot.Reset(); + // Setup "info" to look for a malloc block that contains data + // that is the pointer + range_contains_data_callback_info_t data_info; + data_info.type = eDataTypeHeapInfo; // Check each block for data + data_info.match_count = 0; // Initialize the match count to zero + data_info.done = false; // Set done to false so searching doesn't stop + data_info.unique = false; // Set to true when iterating on the vm_regions + const int check_vm_regions = false; + range_callback_info_t info = {enumerate_range_in_zone, range_info_callback, + &data_info, check_vm_regions}; + foreach_zone_in_this_process(&info); + + // Sort and print byte total bytes + switch (sort_type) { + case eSortTypeNone: + default: + case eSortTypeBytes: + g_objc_class_snapshot.SortByTotalBytes(g_objc_classes, true); + break; + + case eSortTypeCount: + g_objc_class_snapshot.SortByTotalCount(g_objc_classes, true); + break; + } + } else { + printf("error: no objective C classes\n"); + } } //---------------------------------------------------------------------- @@ -1024,28 +865,27 @@ get_heap_info (int sort_type) // // Finds a C string inside one or more currently valid malloc blocks. //---------------------------------------------------------------------- -malloc_match * -find_cstring_in_heap (const char *s, int check_vm_regions) -{ - g_matches.clear(); - if (s == NULL || s[0] == '\0') - { - printf ("error: invalid argument (empty cstring)\n"); - return NULL; - } - // Setup "info" to look for a malloc block that contains data - // that is the C string passed in aligned on a 1 byte boundary - range_contains_data_callback_info_t data_info; - data_info.type = eDataTypeContainsData; // Check each block for data - data_info.data.buffer = (uint8_t *)s; // What data? The C string passed in - data_info.data.size = strlen(s); // How many bytes? The length of the C string - data_info.data.align = 1; // Data doesn't need to be aligned, so set the alignment to 1 - data_info.match_count = 0; // Initialize the match count to zero - data_info.done = false; // Set done to false so searching doesn't stop - data_info.unique = false; // Set to true when iterating on the vm_regions - range_callback_info_t info = { enumerate_range_in_zone, range_info_callback, &data_info, check_vm_regions }; - foreach_zone_in_this_process (&info); - return g_matches.data(); +malloc_match *find_cstring_in_heap(const char *s, int check_vm_regions) { + g_matches.clear(); + if (s == NULL || s[0] == '\0') { + printf("error: invalid argument (empty cstring)\n"); + return NULL; + } + // Setup "info" to look for a malloc block that contains data + // that is the C string passed in aligned on a 1 byte boundary + range_contains_data_callback_info_t data_info; + data_info.type = eDataTypeContainsData; // Check each block for data + data_info.data.buffer = (uint8_t *)s; // What data? The C string passed in + data_info.data.size = strlen(s); // How many bytes? The length of the C string + data_info.data.align = + 1; // Data doesn't need to be aligned, so set the alignment to 1 + data_info.match_count = 0; // Initialize the match count to zero + data_info.done = false; // Set done to false so searching doesn't stop + data_info.unique = false; // Set to true when iterating on the vm_regions + range_callback_info_t info = {enumerate_range_in_zone, range_info_callback, + &data_info, check_vm_regions}; + foreach_zone_in_this_process(&info); + return g_matches.data(); } //---------------------------------------------------------------------- @@ -1053,19 +893,19 @@ find_cstring_in_heap (const char *s, int check_vm_regions) // // Find the malloc block that whose address range contains "addr". //---------------------------------------------------------------------- -malloc_match * -find_block_for_address (const void *addr, int check_vm_regions) -{ - g_matches.clear(); - // Setup "info" to look for a malloc block that contains data - // that is the C string passed in aligned on a 1 byte boundary - range_contains_data_callback_info_t data_info; - data_info.type = eDataTypeAddress; // Check each block to see if the block contains the address passed in - data_info.addr = (uintptr_t)addr; // What data? The C string passed in - data_info.match_count = 0; // Initialize the match count to zero - data_info.done = false; // Set done to false so searching doesn't stop - data_info.unique = false; // Set to true when iterating on the vm_regions - range_callback_info_t info = { enumerate_range_in_zone, range_info_callback, &data_info, check_vm_regions }; - foreach_zone_in_this_process (&info); - return g_matches.data(); +malloc_match *find_block_for_address(const void *addr, int check_vm_regions) { + g_matches.clear(); + // Setup "info" to look for a malloc block that contains data + // that is the C string passed in aligned on a 1 byte boundary + range_contains_data_callback_info_t data_info; + data_info.type = eDataTypeAddress; // Check each block to see if the block + // contains the address passed in + data_info.addr = (uintptr_t)addr; // What data? The C string passed in + data_info.match_count = 0; // Initialize the match count to zero + data_info.done = false; // Set done to false so searching doesn't stop + data_info.unique = false; // Set to true when iterating on the vm_regions + range_callback_info_t info = {enumerate_range_in_zone, range_info_callback, + &data_info, check_vm_regions}; + foreach_zone_in_this_process(&info); + return g_matches.data(); } |