static void gum_sanity_checker_print_instance_leaks_details (GumSanityChecker * self, GumList * stale) { GumList * instances, * walk; instances = gum_list_copy (stale); instances = gum_list_sort_with_data (instances, gum_sanity_checker_compare_instances, self); gum_sanity_checker_print (self, "\tAddress\t\tRefCount\tGType\n"); gum_sanity_checker_print (self, "\t--------\t--------\t-----\n"); for (walk = instances; walk != NULL; walk = walk->next) { GumInstanceDetails details; gum_sanity_checker_details_from_instance (self, &details, walk->data); gum_sanity_checker_printf (self, "\t%p\t%d%s\t%s\n", details.address, details.ref_count, details.ref_count <= 9 ? "\t" : "", details.type_name); } gum_list_free (instances); }
static void gum_sanity_checker_print_block_leaks_summary (GumSanityChecker * self, GumList * block_groups) { GumList * groups, * walk; groups = gum_list_copy (block_groups); groups = gum_list_sort_with_data (groups, gum_sanity_checker_compare_groups, self); gum_sanity_checker_print (self, "\tCount\tSize\n"); gum_sanity_checker_print (self, "\t-----\t----\n"); for (walk = groups; walk != NULL; walk = walk->next) { GumAllocationGroup * group = (GumAllocationGroup *) walk->data; if (group->alive_now == 0) continue; gum_sanity_checker_printf (self, "\t%u\t%u\n", group->alive_now, group->size); } gum_list_free (groups); }
static void gum_sanity_checker_print_instance_leaks_summary (GumSanityChecker * self, GumList * stale) { GumHashTable * count_by_type; GumList * walk, * keys; count_by_type = gum_sanity_checker_count_leaks_by_type_name (self, stale); keys = gum_hash_table_get_keys (count_by_type); keys = gum_list_sort_with_data (keys, gum_sanity_checker_compare_type_names, count_by_type); gum_sanity_checker_print (self, "\tCount\tGType\n"); gum_sanity_checker_print (self, "\t-----\t-----\n"); for (walk = keys; walk != NULL; walk = walk->next) { const gchar * type_name = (const gchar *) walk->data; guint count; count = GPOINTER_TO_UINT (gum_hash_table_lookup (count_by_type, type_name)); gum_sanity_checker_printf (self, "\t%u\t%s\n", count, type_name); } gum_list_free (keys); gum_hash_table_unref (count_by_type); }
void gum_code_allocator_free (GumCodeAllocator * allocator) { gum_list_foreach (allocator->pages, (GFunc) gum_code_page_free, NULL); gum_list_free (allocator->pages); allocator->pages = NULL; }
void gum_cobject_list_free (GumList * cobject_list) { GumList * walk; for (walk = cobject_list; walk != NULL; walk = walk->next) { GumCObject * cobject = walk->data; gum_cobject_free (cobject); } gum_list_free (cobject_list); }
void gum_allocation_block_list_free (GumList * block_list) { GumList * cur; for (cur = block_list; cur != NULL; cur = cur->next) { GumAllocationBlock * block = cur->data; gum_allocation_block_free (block); } gum_list_free (block_list); }
static void gum_sanity_checker_print_block_leaks_details (GumSanityChecker * self, GumList * stale) { GumList * blocks, * walk; blocks = gum_list_copy (stale); blocks = gum_list_sort_with_data (blocks, gum_sanity_checker_compare_blocks, self); gum_sanity_checker_print (self, "\tAddress\t\tSize\n"); gum_sanity_checker_print (self, "\t--------\t----\n"); for (walk = blocks; walk != NULL; walk = walk->next) { GumAllocationBlock * block = (GumAllocationBlock *) walk->data; guint i; gum_sanity_checker_printf (self, "\t%p\t%u\n", block->address, block->size); for (i = 0; i != block->return_addresses.len; i++) { GumReturnAddress addr = block->return_addresses.items[i]; GumReturnAddressDetails rad; if (gum_return_address_details_from_address (addr, &rad)) { gchar * file_basename; file_basename = g_path_get_basename (rad.file_name); gum_sanity_checker_printf (self, "\t %p %s!%s %s:%u\n", rad.address, rad.module_name, rad.function_name, file_basename, rad.line_number); g_free (file_basename); } else { gum_sanity_checker_printf (self, "\t %p\n", addr); } } } gum_list_free (blocks); }
gboolean gum_sanity_checker_end (GumSanityChecker * self) { GumSanityCheckerPrivate * priv = self->priv; gboolean all_checks_passed = TRUE; if (priv->bounds_checker != NULL) { gum_bounds_checker_detach (priv->bounds_checker); g_object_unref (priv->bounds_checker); priv->bounds_checker = NULL; } if (priv->instance_tracker != NULL) { GumList * stale_instances; gum_instance_tracker_end (priv->instance_tracker); stale_instances = gum_instance_tracker_peek_instances (priv->instance_tracker); if (stale_instances != NULL) { all_checks_passed = FALSE; gum_sanity_checker_printf (self, "Instance leaks detected:\n\n"); gum_sanity_checker_print_instance_leaks_summary (self, stale_instances); gum_sanity_checker_print (self, "\n"); gum_sanity_checker_print_instance_leaks_details (self, stale_instances); gum_list_free (stale_instances); } g_object_unref (priv->instance_tracker); priv->instance_tracker = NULL; } if (priv->alloc_probe != NULL) { GumList * stale_blocks; gum_allocator_probe_detach (priv->alloc_probe); stale_blocks = gum_allocation_tracker_peek_block_list (priv->alloc_tracker); if (stale_blocks != NULL) { if (all_checks_passed) { GumList * block_groups; block_groups = gum_allocation_tracker_peek_block_groups (priv->alloc_tracker); gum_sanity_checker_printf (self, "Block leaks detected:\n\n"); gum_sanity_checker_print_block_leaks_summary (self, block_groups); gum_sanity_checker_print (self, "\n"); gum_sanity_checker_print_block_leaks_details (self, stale_blocks); gum_allocation_group_list_free (block_groups); } all_checks_passed = FALSE; gum_allocation_block_list_free (stale_blocks); } g_object_unref (priv->alloc_probe); priv->alloc_probe = NULL; g_object_unref (priv->alloc_tracker); priv->alloc_tracker = NULL; } return all_checks_passed; }