1 /******************************************************************************
3 * Module Name: uttrack - Memory allocation tracking routines (debug only)
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2012, Intel Corp.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
45 * These procedures are used for tracking memory leaks in the subsystem, and
46 * they get compiled out when the ACPI_DBG_TRACK_ALLOCATIONS is not set.
48 * Each memory allocation is tracked via a doubly linked list. Each
49 * element contains the caller's component, module name, function name, and
50 * line number. acpi_ut_allocate and acpi_ut_allocate_zeroed call
51 * acpi_ut_track_allocation to add an element to the list; deletion
52 * occurs in the body of acpi_ut_free.
55 #include <acpi/acpi.h>
58 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
60 #define _COMPONENT ACPI_UTILITIES
61 ACPI_MODULE_NAME("uttrack")
63 /* Local prototypes */
64 static struct acpi_debug_mem_block
*acpi_ut_find_allocation(void *allocation
);
67 acpi_ut_track_allocation(struct acpi_debug_mem_block
*address
,
70 u32 component
, const char *module
, u32 line
);
73 acpi_ut_remove_allocation(struct acpi_debug_mem_block
*address
,
74 u32 component
, const char *module
, u32 line
);
76 /*******************************************************************************
78 * FUNCTION: acpi_ut_create_list
80 * PARAMETERS: cache_name - Ascii name for the cache
81 * object_size - Size of each cached object
82 * return_cache - Where the new cache object is returned
86 * DESCRIPTION: Create a local memory list for tracking purposed
88 ******************************************************************************/
91 acpi_ut_create_list(char *list_name
,
92 u16 object_size
, struct acpi_memory_list
**return_cache
)
94 struct acpi_memory_list
*cache
;
96 cache
= acpi_os_allocate(sizeof(struct acpi_memory_list
));
98 return (AE_NO_MEMORY
);
101 ACPI_MEMSET(cache
, 0, sizeof(struct acpi_memory_list
));
103 cache
->list_name
= list_name
;
104 cache
->object_size
= object_size
;
106 *return_cache
= cache
;
110 /*******************************************************************************
112 * FUNCTION: acpi_ut_allocate_and_track
114 * PARAMETERS: size - Size of the allocation
115 * component - Component type of caller
116 * module - Source file name of caller
117 * line - Line number of caller
119 * RETURN: Address of the allocated memory on success, NULL on failure.
121 * DESCRIPTION: The subsystem's equivalent of malloc.
123 ******************************************************************************/
125 void *acpi_ut_allocate_and_track(acpi_size size
,
126 u32 component
, const char *module
, u32 line
)
128 struct acpi_debug_mem_block
*allocation
;
132 acpi_ut_allocate(size
+ sizeof(struct acpi_debug_mem_header
),
133 component
, module
, line
);
138 status
= acpi_ut_track_allocation(allocation
, size
,
139 ACPI_MEM_MALLOC
, component
, module
,
141 if (ACPI_FAILURE(status
)) {
142 acpi_os_free(allocation
);
146 acpi_gbl_global_list
->total_allocated
++;
147 acpi_gbl_global_list
->total_size
+= (u32
)size
;
148 acpi_gbl_global_list
->current_total_size
+= (u32
)size
;
149 if (acpi_gbl_global_list
->current_total_size
>
150 acpi_gbl_global_list
->max_occupied
) {
151 acpi_gbl_global_list
->max_occupied
=
152 acpi_gbl_global_list
->current_total_size
;
155 return ((void *)&allocation
->user_space
);
158 /*******************************************************************************
160 * FUNCTION: acpi_ut_allocate_zeroed_and_track
162 * PARAMETERS: size - Size of the allocation
163 * component - Component type of caller
164 * module - Source file name of caller
165 * line - Line number of caller
167 * RETURN: Address of the allocated memory on success, NULL on failure.
169 * DESCRIPTION: Subsystem equivalent of calloc.
171 ******************************************************************************/
173 void *acpi_ut_allocate_zeroed_and_track(acpi_size size
,
175 const char *module
, u32 line
)
177 struct acpi_debug_mem_block
*allocation
;
181 acpi_ut_allocate_zeroed(size
+ sizeof(struct acpi_debug_mem_header
),
182 component
, module
, line
);
185 /* Report allocation error */
187 ACPI_ERROR((module
, line
,
188 "Could not allocate size %u", (u32
)size
));
192 status
= acpi_ut_track_allocation(allocation
, size
,
193 ACPI_MEM_CALLOC
, component
, module
,
195 if (ACPI_FAILURE(status
)) {
196 acpi_os_free(allocation
);
200 acpi_gbl_global_list
->total_allocated
++;
201 acpi_gbl_global_list
->total_size
+= (u32
)size
;
202 acpi_gbl_global_list
->current_total_size
+= (u32
)size
;
203 if (acpi_gbl_global_list
->current_total_size
>
204 acpi_gbl_global_list
->max_occupied
) {
205 acpi_gbl_global_list
->max_occupied
=
206 acpi_gbl_global_list
->current_total_size
;
209 return ((void *)&allocation
->user_space
);
212 /*******************************************************************************
214 * FUNCTION: acpi_ut_free_and_track
216 * PARAMETERS: allocation - Address of the memory to deallocate
217 * component - Component type of caller
218 * module - Source file name of caller
219 * line - Line number of caller
223 * DESCRIPTION: Frees the memory at Allocation
225 ******************************************************************************/
228 acpi_ut_free_and_track(void *allocation
,
229 u32 component
, const char *module
, u32 line
)
231 struct acpi_debug_mem_block
*debug_block
;
234 ACPI_FUNCTION_TRACE_PTR(ut_free
, allocation
);
236 if (NULL
== allocation
) {
237 ACPI_ERROR((module
, line
, "Attempt to delete a NULL address"));
242 debug_block
= ACPI_CAST_PTR(struct acpi_debug_mem_block
,
243 (((char *)allocation
) -
244 sizeof(struct acpi_debug_mem_header
)));
246 acpi_gbl_global_list
->total_freed
++;
247 acpi_gbl_global_list
->current_total_size
-= debug_block
->size
;
249 status
= acpi_ut_remove_allocation(debug_block
,
250 component
, module
, line
);
251 if (ACPI_FAILURE(status
)) {
252 ACPI_EXCEPTION((AE_INFO
, status
, "Could not free memory"));
255 acpi_os_free(debug_block
);
256 ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS
, "%p freed\n", allocation
));
260 /*******************************************************************************
262 * FUNCTION: acpi_ut_find_allocation
264 * PARAMETERS: allocation - Address of allocated memory
266 * RETURN: A list element if found; NULL otherwise.
268 * DESCRIPTION: Searches for an element in the global allocation tracking list.
270 ******************************************************************************/
272 static struct acpi_debug_mem_block
*acpi_ut_find_allocation(void *allocation
)
274 struct acpi_debug_mem_block
*element
;
276 ACPI_FUNCTION_ENTRY();
278 element
= acpi_gbl_global_list
->list_head
;
280 /* Search for the address. */
283 if (element
== allocation
) {
287 element
= element
->next
;
293 /*******************************************************************************
295 * FUNCTION: acpi_ut_track_allocation
297 * PARAMETERS: allocation - Address of allocated memory
298 * size - Size of the allocation
299 * alloc_type - MEM_MALLOC or MEM_CALLOC
300 * component - Component type of caller
301 * module - Source file name of caller
302 * line - Line number of caller
306 * DESCRIPTION: Inserts an element into the global allocation tracking list.
308 ******************************************************************************/
311 acpi_ut_track_allocation(struct acpi_debug_mem_block
*allocation
,
314 u32 component
, const char *module
, u32 line
)
316 struct acpi_memory_list
*mem_list
;
317 struct acpi_debug_mem_block
*element
;
318 acpi_status status
= AE_OK
;
320 ACPI_FUNCTION_TRACE_PTR(ut_track_allocation
, allocation
);
322 if (acpi_gbl_disable_mem_tracking
) {
323 return_ACPI_STATUS(AE_OK
);
326 mem_list
= acpi_gbl_global_list
;
327 status
= acpi_ut_acquire_mutex(ACPI_MTX_MEMORY
);
328 if (ACPI_FAILURE(status
)) {
329 return_ACPI_STATUS(status
);
333 * Search list for this address to make sure it is not already on the list.
334 * This will catch several kinds of problems.
336 element
= acpi_ut_find_allocation(allocation
);
339 "UtTrackAllocation: Allocation already present in list! (%p)",
342 ACPI_ERROR((AE_INFO
, "Element %p Address %p",
343 element
, allocation
));
345 goto unlock_and_exit
;
348 /* Fill in the instance data. */
350 allocation
->size
= (u32
)size
;
351 allocation
->alloc_type
= alloc_type
;
352 allocation
->component
= component
;
353 allocation
->line
= line
;
355 ACPI_STRNCPY(allocation
->module
, module
, ACPI_MAX_MODULE_NAME
);
356 allocation
->module
[ACPI_MAX_MODULE_NAME
- 1] = 0;
358 /* Insert at list head */
360 if (mem_list
->list_head
) {
361 ((struct acpi_debug_mem_block
*)(mem_list
->list_head
))->
362 previous
= allocation
;
365 allocation
->next
= mem_list
->list_head
;
366 allocation
->previous
= NULL
;
368 mem_list
->list_head
= allocation
;
371 status
= acpi_ut_release_mutex(ACPI_MTX_MEMORY
);
372 return_ACPI_STATUS(status
);
375 /*******************************************************************************
377 * FUNCTION: acpi_ut_remove_allocation
379 * PARAMETERS: allocation - Address of allocated memory
380 * component - Component type of caller
381 * module - Source file name of caller
382 * line - Line number of caller
386 * DESCRIPTION: Deletes an element from the global allocation tracking list.
388 ******************************************************************************/
391 acpi_ut_remove_allocation(struct acpi_debug_mem_block
*allocation
,
392 u32 component
, const char *module
, u32 line
)
394 struct acpi_memory_list
*mem_list
;
397 ACPI_FUNCTION_TRACE(ut_remove_allocation
);
399 if (acpi_gbl_disable_mem_tracking
) {
400 return_ACPI_STATUS(AE_OK
);
403 mem_list
= acpi_gbl_global_list
;
404 if (NULL
== mem_list
->list_head
) {
406 /* No allocations! */
408 ACPI_ERROR((module
, line
,
409 "Empty allocation list, nothing to free!"));
411 return_ACPI_STATUS(AE_OK
);
414 status
= acpi_ut_acquire_mutex(ACPI_MTX_MEMORY
);
415 if (ACPI_FAILURE(status
)) {
416 return_ACPI_STATUS(status
);
421 if (allocation
->previous
) {
422 (allocation
->previous
)->next
= allocation
->next
;
424 mem_list
->list_head
= allocation
->next
;
427 if (allocation
->next
) {
428 (allocation
->next
)->previous
= allocation
->previous
;
431 /* Mark the segment as deleted */
433 ACPI_MEMSET(&allocation
->user_space
, 0xEA, allocation
->size
);
435 ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS
, "Freeing size 0%X\n",
438 status
= acpi_ut_release_mutex(ACPI_MTX_MEMORY
);
439 return_ACPI_STATUS(status
);
442 /*******************************************************************************
444 * FUNCTION: acpi_ut_dump_allocation_info
450 * DESCRIPTION: Print some info about the outstanding allocations.
452 ******************************************************************************/
454 void acpi_ut_dump_allocation_info(void)
457 struct acpi_memory_list *mem_list;
460 ACPI_FUNCTION_TRACE(ut_dump_allocation_info
);
463 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
464 ("%30s: %4d (%3d Kb)\n", "Current allocations",
465 mem_list->current_count,
466 ROUND_UP_TO_1K (mem_list->current_size)));
468 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
469 ("%30s: %4d (%3d Kb)\n", "Max concurrent allocations",
470 mem_list->max_concurrent_count,
471 ROUND_UP_TO_1K (mem_list->max_concurrent_size)));
473 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
474 ("%30s: %4d (%3d Kb)\n", "Total (all) internal objects",
475 running_object_count,
476 ROUND_UP_TO_1K (running_object_size)));
478 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
479 ("%30s: %4d (%3d Kb)\n", "Total (all) allocations",
481 ROUND_UP_TO_1K (running_alloc_size)));
483 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
484 ("%30s: %4d (%3d Kb)\n", "Current Nodes",
485 acpi_gbl_current_node_count,
486 ROUND_UP_TO_1K (acpi_gbl_current_node_size)));
488 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
489 ("%30s: %4d (%3d Kb)\n", "Max Nodes",
490 acpi_gbl_max_concurrent_node_count,
491 ROUND_UP_TO_1K ((acpi_gbl_max_concurrent_node_count *
492 sizeof (struct acpi_namespace_node)))));
497 /*******************************************************************************
499 * FUNCTION: acpi_ut_dump_allocations
501 * PARAMETERS: component - Component(s) to dump info for.
502 * module - Module to dump info for. NULL means all.
506 * DESCRIPTION: Print a list of all outstanding allocations.
508 ******************************************************************************/
510 void acpi_ut_dump_allocations(u32 component
, const char *module
)
512 struct acpi_debug_mem_block
*element
;
513 union acpi_descriptor
*descriptor
;
514 u32 num_outstanding
= 0;
517 ACPI_FUNCTION_TRACE(ut_dump_allocations
);
519 if (acpi_gbl_disable_mem_tracking
) {
524 * Walk the allocation list.
526 if (ACPI_FAILURE(acpi_ut_acquire_mutex(ACPI_MTX_MEMORY
))) {
530 element
= acpi_gbl_global_list
->list_head
;
532 if ((element
->component
& component
) &&
534 || (0 == ACPI_STRCMP(module
, element
->module
)))) {
536 ACPI_CAST_PTR(union acpi_descriptor
,
537 &element
->user_space
);
540 sizeof(struct acpi_common_descriptor
)) {
541 acpi_os_printf("%p Length 0x%04X %9.9s-%u "
542 "[Not a Descriptor - too small]\n",
543 descriptor
, element
->size
,
544 element
->module
, element
->line
);
546 /* Ignore allocated objects that are in a cache */
548 if (ACPI_GET_DESCRIPTOR_TYPE(descriptor
) !=
549 ACPI_DESC_TYPE_CACHED
) {
551 ("%p Length 0x%04X %9.9s-%u [%s] ",
552 descriptor
, element
->size
,
553 element
->module
, element
->line
,
554 acpi_ut_get_descriptor_name
557 /* Validate the descriptor type using Type field and length */
559 descriptor_type
= 0; /* Not a valid descriptor type */
561 switch (ACPI_GET_DESCRIPTOR_TYPE
563 case ACPI_DESC_TYPE_OPERAND
:
566 acpi_operand_object
))
569 ACPI_DESC_TYPE_OPERAND
;
573 case ACPI_DESC_TYPE_PARSER
:
576 acpi_parse_object
)) {
578 ACPI_DESC_TYPE_PARSER
;
582 case ACPI_DESC_TYPE_NAMED
:
585 acpi_namespace_node
))
588 ACPI_DESC_TYPE_NAMED
;
596 /* Display additional info for the major descriptor types */
598 switch (descriptor_type
) {
599 case ACPI_DESC_TYPE_OPERAND
:
601 ("%12.12s RefCount 0x%04X\n",
602 acpi_ut_get_type_name
603 (descriptor
->object
.common
.
605 descriptor
->object
.common
.
609 case ACPI_DESC_TYPE_PARSER
:
611 ("AmlOpcode 0x%04hX\n",
616 case ACPI_DESC_TYPE_NAMED
:
617 acpi_os_printf("%4.4s\n",
618 acpi_ut_get_node_name
624 acpi_os_printf("\n");
633 element
= element
->next
;
636 (void)acpi_ut_release_mutex(ACPI_MTX_MEMORY
);
640 if (!num_outstanding
) {
641 ACPI_INFO((AE_INFO
, "No outstanding allocations"));
643 ACPI_ERROR((AE_INFO
, "%u(0x%X) Outstanding allocations",
644 num_outstanding
, num_outstanding
));
650 #endif /* ACPI_DBG_TRACK_ALLOCATIONS */