brintos

brintos / linux-shallow public Read only

0
0
Text · 18.6 KiB · f5f5da4 Raw
706 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: uttrack - Memory allocation tracking routines (debug only)5 *6 * Copyright (C) 2000 - 2023, Intel Corp.7 *8 *****************************************************************************/9 10/*11 * These procedures are used for tracking memory leaks in the subsystem, and12 * they get compiled out when the ACPI_DBG_TRACK_ALLOCATIONS is not set.13 *14 * Each memory allocation is tracked via a doubly linked list. Each15 * element contains the caller's component, module name, function name, and16 * line number. acpi_ut_allocate and acpi_ut_allocate_zeroed call17 * acpi_ut_track_allocation to add an element to the list; deletion18 * occurs in the body of acpi_ut_free.19 */20 21#include <acpi/acpi.h>22#include "accommon.h"23 24#ifdef ACPI_DBG_TRACK_ALLOCATIONS25 26#define _COMPONENT          ACPI_UTILITIES27ACPI_MODULE_NAME("uttrack")28 29/* Local prototypes */30static struct acpi_debug_mem_block *acpi_ut_find_allocation(struct31							    acpi_debug_mem_block32							    *allocation);33 34static acpi_status35acpi_ut_track_allocation(struct acpi_debug_mem_block *address,36			 acpi_size size,37			 u8 alloc_type,38			 u32 component, const char *module, u32 line);39 40static acpi_status41acpi_ut_remove_allocation(struct acpi_debug_mem_block *address,42			  u32 component, const char *module, u32 line);43 44/*******************************************************************************45 *46 * FUNCTION:    acpi_ut_create_list47 *48 * PARAMETERS:  cache_name      - Ascii name for the cache49 *              object_size     - Size of each cached object50 *              return_cache    - Where the new cache object is returned51 *52 * RETURN:      Status53 *54 * DESCRIPTION: Create a local memory list for tracking purposed55 *56 ******************************************************************************/57 58acpi_status59acpi_ut_create_list(const char *list_name,60		    u16 object_size, struct acpi_memory_list **return_cache)61{62	struct acpi_memory_list *cache;63 64	cache = acpi_os_allocate_zeroed(sizeof(struct acpi_memory_list));65	if (!cache) {66		return (AE_NO_MEMORY);67	}68 69	cache->list_name = list_name;70	cache->object_size = object_size;71 72	*return_cache = cache;73	return (AE_OK);74}75 76/*******************************************************************************77 *78 * FUNCTION:    acpi_ut_allocate_and_track79 *80 * PARAMETERS:  size                - Size of the allocation81 *              component           - Component type of caller82 *              module              - Source file name of caller83 *              line                - Line number of caller84 *85 * RETURN:      Address of the allocated memory on success, NULL on failure.86 *87 * DESCRIPTION: The subsystem's equivalent of malloc.88 *89 ******************************************************************************/90 91void *acpi_ut_allocate_and_track(acpi_size size,92				 u32 component, const char *module, u32 line)93{94	struct acpi_debug_mem_block *allocation;95	acpi_status status;96 97	/* Check for an inadvertent size of zero bytes */98 99	if (!size) {100		ACPI_WARNING((module, line,101			      "Attempt to allocate zero bytes, allocating 1 byte"));102		size = 1;103	}104 105	allocation =106	    acpi_os_allocate(size + sizeof(struct acpi_debug_mem_header));107	if (!allocation) {108 109		/* Report allocation error */110 111		ACPI_WARNING((module, line,112			      "Could not allocate size %u", (u32)size));113 114		return (NULL);115	}116 117	status =118	    acpi_ut_track_allocation(allocation, size, ACPI_MEM_MALLOC,119				     component, module, line);120	if (ACPI_FAILURE(status)) {121		acpi_os_free(allocation);122		return (NULL);123	}124 125	acpi_gbl_global_list->total_allocated++;126	acpi_gbl_global_list->total_size += (u32)size;127	acpi_gbl_global_list->current_total_size += (u32)size;128 129	if (acpi_gbl_global_list->current_total_size >130	    acpi_gbl_global_list->max_occupied) {131		acpi_gbl_global_list->max_occupied =132		    acpi_gbl_global_list->current_total_size;133	}134 135	return ((void *)&allocation->user_space);136}137 138/*******************************************************************************139 *140 * FUNCTION:    acpi_ut_allocate_zeroed_and_track141 *142 * PARAMETERS:  size                - Size of the allocation143 *              component           - Component type of caller144 *              module              - Source file name of caller145 *              line                - Line number of caller146 *147 * RETURN:      Address of the allocated memory on success, NULL on failure.148 *149 * DESCRIPTION: Subsystem equivalent of calloc.150 *151 ******************************************************************************/152 153void *acpi_ut_allocate_zeroed_and_track(acpi_size size,154					u32 component,155					const char *module, u32 line)156{157	struct acpi_debug_mem_block *allocation;158	acpi_status status;159 160	/* Check for an inadvertent size of zero bytes */161 162	if (!size) {163		ACPI_WARNING((module, line,164			      "Attempt to allocate zero bytes, allocating 1 byte"));165		size = 1;166	}167 168	allocation =169	    acpi_os_allocate_zeroed(size +170				    sizeof(struct acpi_debug_mem_header));171	if (!allocation) {172 173		/* Report allocation error */174 175		ACPI_ERROR((module, line,176			    "Could not allocate size %u", (u32)size));177		return (NULL);178	}179 180	status = acpi_ut_track_allocation(allocation, size,181					  ACPI_MEM_CALLOC, component, module,182					  line);183	if (ACPI_FAILURE(status)) {184		acpi_os_free(allocation);185		return (NULL);186	}187 188	acpi_gbl_global_list->total_allocated++;189	acpi_gbl_global_list->total_size += (u32)size;190	acpi_gbl_global_list->current_total_size += (u32)size;191 192	if (acpi_gbl_global_list->current_total_size >193	    acpi_gbl_global_list->max_occupied) {194		acpi_gbl_global_list->max_occupied =195		    acpi_gbl_global_list->current_total_size;196	}197 198	return ((void *)&allocation->user_space);199}200 201/*******************************************************************************202 *203 * FUNCTION:    acpi_ut_free_and_track204 *205 * PARAMETERS:  allocation          - Address of the memory to deallocate206 *              component           - Component type of caller207 *              module              - Source file name of caller208 *              line                - Line number of caller209 *210 * RETURN:      None211 *212 * DESCRIPTION: Frees the memory at Allocation213 *214 ******************************************************************************/215 216void217acpi_ut_free_and_track(void *allocation,218		       u32 component, const char *module, u32 line)219{220	struct acpi_debug_mem_block *debug_block;221	acpi_status status;222 223	ACPI_FUNCTION_TRACE_PTR(ut_free, allocation);224 225	if (NULL == allocation) {226		ACPI_ERROR((module, line, "Attempt to delete a NULL address"));227 228		return_VOID;229	}230 231	debug_block = ACPI_CAST_PTR(struct acpi_debug_mem_block,232				    (((char *)allocation) -233				     sizeof(struct acpi_debug_mem_header)));234 235	acpi_gbl_global_list->total_freed++;236	acpi_gbl_global_list->current_total_size -= debug_block->size;237 238	status =239	    acpi_ut_remove_allocation(debug_block, component, module, line);240	if (ACPI_FAILURE(status)) {241		ACPI_EXCEPTION((AE_INFO, status, "Could not free memory"));242	}243 244	acpi_os_free(debug_block);245	ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "%p freed (block %p)\n",246			  allocation, debug_block));247	return_VOID;248}249 250/*******************************************************************************251 *252 * FUNCTION:    acpi_ut_find_allocation253 *254 * PARAMETERS:  allocation              - Address of allocated memory255 *256 * RETURN:      Three cases:257 *              1) List is empty, NULL is returned.258 *              2) Element was found. Returns Allocation parameter.259 *              3) Element was not found. Returns position where it should be260 *                  inserted into the list.261 *262 * DESCRIPTION: Searches for an element in the global allocation tracking list.263 *              If the element is not found, returns the location within the264 *              list where the element should be inserted.265 *266 *              Note: The list is ordered by larger-to-smaller addresses.267 *268 *              This global list is used to detect memory leaks in ACPICA as269 *              well as other issues such as an attempt to release the same270 *              internal object more than once. Although expensive as far271 *              as cpu time, this list is much more helpful for finding these272 *              types of issues than using memory leak detectors outside of273 *              the ACPICA code.274 *275 ******************************************************************************/276 277static struct acpi_debug_mem_block *acpi_ut_find_allocation(struct278							    acpi_debug_mem_block279							    *allocation)280{281	struct acpi_debug_mem_block *element;282 283	element = acpi_gbl_global_list->list_head;284	if (!element) {285		return (NULL);286	}287 288	/*289	 * Search for the address.290	 *291	 * Note: List is ordered by larger-to-smaller addresses, on the292	 * assumption that a new allocation usually has a larger address293	 * than previous allocations.294	 */295	while (element > allocation) {296 297		/* Check for end-of-list */298 299		if (!element->next) {300			return (element);301		}302 303		element = element->next;304	}305 306	if (element == allocation) {307		return (element);308	}309 310	return (element->previous);311}312 313/*******************************************************************************314 *315 * FUNCTION:    acpi_ut_track_allocation316 *317 * PARAMETERS:  allocation          - Address of allocated memory318 *              size                - Size of the allocation319 *              alloc_type          - MEM_MALLOC or MEM_CALLOC320 *              component           - Component type of caller321 *              module              - Source file name of caller322 *              line                - Line number of caller323 *324 * RETURN:      Status325 *326 * DESCRIPTION: Inserts an element into the global allocation tracking list.327 *328 ******************************************************************************/329 330static acpi_status331acpi_ut_track_allocation(struct acpi_debug_mem_block *allocation,332			 acpi_size size,333			 u8 alloc_type,334			 u32 component, const char *module, u32 line)335{336	struct acpi_memory_list *mem_list;337	struct acpi_debug_mem_block *element;338	acpi_status status = AE_OK;339 340	ACPI_FUNCTION_TRACE_PTR(ut_track_allocation, allocation);341 342	if (acpi_gbl_disable_mem_tracking) {343		return_ACPI_STATUS(AE_OK);344	}345 346	mem_list = acpi_gbl_global_list;347	status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY);348	if (ACPI_FAILURE(status)) {349		return_ACPI_STATUS(status);350	}351 352	/*353	 * Search the global list for this address to make sure it is not354	 * already present. This will catch several kinds of problems.355	 */356	element = acpi_ut_find_allocation(allocation);357	if (element == allocation) {358		ACPI_ERROR((AE_INFO,359			    "UtTrackAllocation: Allocation (%p) already present in global list!",360			    allocation));361		goto unlock_and_exit;362	}363 364	/* Fill in the instance data */365 366	allocation->size = (u32)size;367	allocation->alloc_type = alloc_type;368	allocation->component = component;369	allocation->line = line;370 371	acpi_ut_safe_strncpy(allocation->module, (char *)module,372			     ACPI_MAX_MODULE_NAME);373 374	if (!element) {375 376		/* Insert at list head */377 378		if (mem_list->list_head) {379			((struct acpi_debug_mem_block *)(mem_list->list_head))->380			    previous = allocation;381		}382 383		allocation->next = mem_list->list_head;384		allocation->previous = NULL;385 386		mem_list->list_head = allocation;387	} else {388		/* Insert after element */389 390		allocation->next = element->next;391		allocation->previous = element;392 393		if (element->next) {394			(element->next)->previous = allocation;395		}396 397		element->next = allocation;398	}399 400unlock_and_exit:401	status = acpi_ut_release_mutex(ACPI_MTX_MEMORY);402	return_ACPI_STATUS(status);403}404 405/*******************************************************************************406 *407 * FUNCTION:    acpi_ut_remove_allocation408 *409 * PARAMETERS:  allocation          - Address of allocated memory410 *              component           - Component type of caller411 *              module              - Source file name of caller412 *              line                - Line number of caller413 *414 * RETURN:      Status415 *416 * DESCRIPTION: Deletes an element from the global allocation tracking list.417 *418 ******************************************************************************/419 420static acpi_status421acpi_ut_remove_allocation(struct acpi_debug_mem_block *allocation,422			  u32 component, const char *module, u32 line)423{424	struct acpi_memory_list *mem_list;425	acpi_status status;426 427	ACPI_FUNCTION_NAME(ut_remove_allocation);428 429	if (acpi_gbl_disable_mem_tracking) {430		return (AE_OK);431	}432 433	mem_list = acpi_gbl_global_list;434	if (NULL == mem_list->list_head) {435 436		/* No allocations! */437 438		ACPI_ERROR((module, line,439			    "Empty allocation list, nothing to free!"));440 441		return (AE_OK);442	}443 444	status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY);445	if (ACPI_FAILURE(status)) {446		return (status);447	}448 449	/* Unlink */450 451	if (allocation->previous) {452		(allocation->previous)->next = allocation->next;453	} else {454		mem_list->list_head = allocation->next;455	}456 457	if (allocation->next) {458		(allocation->next)->previous = allocation->previous;459	}460 461	ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Freeing %p, size 0%X\n",462			  &allocation->user_space, allocation->size));463 464	/* Mark the segment as deleted */465 466	memset(&allocation->user_space, 0xEA, allocation->size);467 468	status = acpi_ut_release_mutex(ACPI_MTX_MEMORY);469	return (status);470}471 472/*******************************************************************************473 *474 * FUNCTION:    acpi_ut_dump_allocation_info475 *476 * PARAMETERS:  None477 *478 * RETURN:      None479 *480 * DESCRIPTION: Print some info about the outstanding allocations.481 *482 ******************************************************************************/483 484void acpi_ut_dump_allocation_info(void)485{486/*487	struct acpi_memory_list         *mem_list;488*/489 490	ACPI_FUNCTION_TRACE(ut_dump_allocation_info);491 492/*493	ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,494		("%30s: %4d (%3d Kb)\n", "Current allocations",495		mem_list->current_count,496		ROUND_UP_TO_1K (mem_list->current_size)));497 498	ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,499		("%30s: %4d (%3d Kb)\n", "Max concurrent allocations",500		mem_list->max_concurrent_count,501		ROUND_UP_TO_1K (mem_list->max_concurrent_size)));502 503	ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,504		("%30s: %4d (%3d Kb)\n", "Total (all) internal objects",505		running_object_count,506		ROUND_UP_TO_1K (running_object_size)));507 508	ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,509		("%30s: %4d (%3d Kb)\n", "Total (all) allocations",510		running_alloc_count,511		ROUND_UP_TO_1K (running_alloc_size)));512 513	ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,514		("%30s: %4d (%3d Kb)\n", "Current Nodes",515		acpi_gbl_current_node_count,516		ROUND_UP_TO_1K (acpi_gbl_current_node_size)));517 518	ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,519		("%30s: %4d (%3d Kb)\n", "Max Nodes",520		acpi_gbl_max_concurrent_node_count,521		ROUND_UP_TO_1K ((acpi_gbl_max_concurrent_node_count *522			sizeof (struct acpi_namespace_node)))));523*/524	return_VOID;525}526 527/*******************************************************************************528 *529 * FUNCTION:    acpi_ut_dump_allocations530 *531 * PARAMETERS:  component           - Component(s) to dump info for.532 *              module              - Module to dump info for. NULL means all.533 *534 * RETURN:      None535 *536 * DESCRIPTION: Print a list of all outstanding allocations.537 *538 ******************************************************************************/539 540void acpi_ut_dump_allocations(u32 component, const char *module)541{542	struct acpi_debug_mem_block *element;543	union acpi_descriptor *descriptor;544	u32 num_outstanding = 0;545	u8 descriptor_type;546 547	ACPI_FUNCTION_TRACE(ut_dump_allocations);548 549	if (acpi_gbl_disable_mem_tracking) {550		return_VOID;551	}552 553	/*554	 * Walk the allocation list.555	 */556	if (ACPI_FAILURE(acpi_ut_acquire_mutex(ACPI_MTX_MEMORY))) {557		return_VOID;558	}559 560	if (!acpi_gbl_global_list) {561		goto exit;562	}563 564	element = acpi_gbl_global_list->list_head;565	while (element) {566		if ((element->component & component) &&567		    ((module == NULL)568		     || (0 == strcmp(module, element->module)))) {569			descriptor =570			    ACPI_CAST_PTR(union acpi_descriptor,571					  &element->user_space);572 573			if (element->size <574			    sizeof(struct acpi_common_descriptor)) {575				acpi_os_printf("%p Length 0x%04X %9.9s-%4.4u "576					       "[Not a Descriptor - too small]\n",577					       descriptor, element->size,578					       element->module, element->line);579			} else {580				/* Ignore allocated objects that are in a cache */581 582				if (ACPI_GET_DESCRIPTOR_TYPE(descriptor) !=583				    ACPI_DESC_TYPE_CACHED) {584					acpi_os_printf585					    ("%p Length 0x%04X %9.9s-%4.4u [%s] ",586					     descriptor, element->size,587					     element->module, element->line,588					     acpi_ut_get_descriptor_name589					     (descriptor));590 591					/* Optional object hex dump */592 593					if (acpi_gbl_verbose_leak_dump) {594						acpi_os_printf("\n");595						acpi_ut_dump_buffer((u8 *)596								    descriptor,597								    element->598								    size,599								    DB_BYTE_DISPLAY,600								    0);601					}602 603					/* Validate the descriptor type using Type field and length */604 605					descriptor_type = 0;	/* Not a valid descriptor type */606 607					switch (ACPI_GET_DESCRIPTOR_TYPE608						(descriptor)) {609					case ACPI_DESC_TYPE_OPERAND:610 611						if (element->size ==612						    sizeof(union613							   acpi_operand_object))614						{615							descriptor_type =616							    ACPI_DESC_TYPE_OPERAND;617						}618						break;619 620					case ACPI_DESC_TYPE_PARSER:621 622						if (element->size ==623						    sizeof(union624							   acpi_parse_object)) {625							descriptor_type =626							    ACPI_DESC_TYPE_PARSER;627						}628						break;629 630					case ACPI_DESC_TYPE_NAMED:631 632						if (element->size ==633						    sizeof(struct634							   acpi_namespace_node))635						{636							descriptor_type =637							    ACPI_DESC_TYPE_NAMED;638						}639						break;640 641					default:642 643						break;644					}645 646					/* Display additional info for the major descriptor types */647 648					switch (descriptor_type) {649					case ACPI_DESC_TYPE_OPERAND:650 651						acpi_os_printf652						    ("%12.12s RefCount 0x%04X\n",653						     acpi_ut_get_type_name654						     (descriptor->object.common.655						      type),656						     descriptor->object.common.657						     reference_count);658						break;659 660					case ACPI_DESC_TYPE_PARSER:661 662						acpi_os_printf663						    ("AmlOpcode 0x%04X\n",664						     descriptor->op.asl.665						     aml_opcode);666						break;667 668					case ACPI_DESC_TYPE_NAMED:669 670						acpi_os_printf("%4.4s\n",671							       acpi_ut_get_node_name672							       (&descriptor->673								node));674						break;675 676					default:677 678						acpi_os_printf("\n");679						break;680					}681				}682			}683 684			num_outstanding++;685		}686 687		element = element->next;688	}689 690exit:691	(void)acpi_ut_release_mutex(ACPI_MTX_MEMORY);692 693	/* Print summary */694 695	if (!num_outstanding) {696		ACPI_INFO(("No outstanding allocations"));697	} else {698		ACPI_ERROR((AE_INFO, "%u (0x%X) Outstanding cache allocations",699			    num_outstanding, num_outstanding));700	}701 702	return_VOID;703}704 705#endif				/* ACPI_DBG_TRACK_ALLOCATIONS */706