1 /******************************************************************************
3 * Module Name: uttrack - Memory allocation tracking routines (debug only)
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2013, 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. AcpiUtAllocate and AcpiUtAllocateZeroed call
51 * AcpiUtTrackAllocation to add an element to the list; deletion
52 * occurs in the body of AcpiUtFree.
60 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
62 #define _COMPONENT ACPI_UTILITIES
63 ACPI_MODULE_NAME ("uttrack")
66 /* Local prototypes */
68 static ACPI_DEBUG_MEM_BLOCK
*
69 AcpiUtFindAllocation (
70 ACPI_DEBUG_MEM_BLOCK
*Allocation
);
73 AcpiUtTrackAllocation (
74 ACPI_DEBUG_MEM_BLOCK
*Address
,
82 AcpiUtRemoveAllocation (
83 ACPI_DEBUG_MEM_BLOCK
*Address
,
89 /*******************************************************************************
91 * FUNCTION: AcpiUtCreateList
93 * PARAMETERS: CacheName - Ascii name for the cache
94 * ObjectSize - Size of each cached object
95 * ReturnCache - Where the new cache object is returned
99 * DESCRIPTION: Create a local memory list for tracking purposed
101 ******************************************************************************/
107 ACPI_MEMORY_LIST
**ReturnCache
)
109 ACPI_MEMORY_LIST
*Cache
;
112 Cache
= AcpiOsAllocate (sizeof (ACPI_MEMORY_LIST
));
115 return (AE_NO_MEMORY
);
118 ACPI_MEMSET (Cache
, 0, sizeof (ACPI_MEMORY_LIST
));
120 Cache
->ListName
= ListName
;
121 Cache
->ObjectSize
= ObjectSize
;
123 *ReturnCache
= Cache
;
128 /*******************************************************************************
130 * FUNCTION: AcpiUtAllocateAndTrack
132 * PARAMETERS: Size - Size of the allocation
133 * Component - Component type of caller
134 * Module - Source file name of caller
135 * Line - Line number of caller
137 * RETURN: Address of the allocated memory on success, NULL on failure.
139 * DESCRIPTION: The subsystem's equivalent of malloc.
141 ******************************************************************************/
144 AcpiUtAllocateAndTrack (
150 ACPI_DEBUG_MEM_BLOCK
*Allocation
;
154 /* Check for an inadvertent size of zero bytes */
158 ACPI_WARNING ((Module
, Line
,
159 "Attempt to allocate zero bytes, allocating 1 byte"));
163 Allocation
= AcpiOsAllocate (Size
+ sizeof (ACPI_DEBUG_MEM_HEADER
));
166 /* Report allocation error */
168 ACPI_WARNING ((Module
, Line
,
169 "Could not allocate size %u", (UINT32
) Size
));
174 Status
= AcpiUtTrackAllocation (Allocation
, Size
,
175 ACPI_MEM_MALLOC
, Component
, Module
, Line
);
176 if (ACPI_FAILURE (Status
))
178 AcpiOsFree (Allocation
);
182 AcpiGbl_GlobalList
->TotalAllocated
++;
183 AcpiGbl_GlobalList
->TotalSize
+= (UINT32
) Size
;
184 AcpiGbl_GlobalList
->CurrentTotalSize
+= (UINT32
) Size
;
185 if (AcpiGbl_GlobalList
->CurrentTotalSize
> AcpiGbl_GlobalList
->MaxOccupied
)
187 AcpiGbl_GlobalList
->MaxOccupied
= AcpiGbl_GlobalList
->CurrentTotalSize
;
190 return ((void *) &Allocation
->UserSpace
);
194 /*******************************************************************************
196 * FUNCTION: AcpiUtAllocateZeroedAndTrack
198 * PARAMETERS: Size - Size of the allocation
199 * Component - Component type of caller
200 * Module - Source file name of caller
201 * Line - Line number of caller
203 * RETURN: Address of the allocated memory on success, NULL on failure.
205 * DESCRIPTION: Subsystem equivalent of calloc.
207 ******************************************************************************/
210 AcpiUtAllocateZeroedAndTrack (
216 ACPI_DEBUG_MEM_BLOCK
*Allocation
;
220 /* Check for an inadvertent size of zero bytes */
224 ACPI_WARNING ((Module
, Line
,
225 "Attempt to allocate zero bytes, allocating 1 byte"));
229 Allocation
= AcpiOsAllocateZeroed (Size
+ sizeof (ACPI_DEBUG_MEM_HEADER
));
232 /* Report allocation error */
234 ACPI_ERROR ((Module
, Line
,
235 "Could not allocate size %u", (UINT32
) Size
));
239 Status
= AcpiUtTrackAllocation (Allocation
, Size
,
240 ACPI_MEM_CALLOC
, Component
, Module
, Line
);
241 if (ACPI_FAILURE (Status
))
243 AcpiOsFree (Allocation
);
247 AcpiGbl_GlobalList
->TotalAllocated
++;
248 AcpiGbl_GlobalList
->TotalSize
+= (UINT32
) Size
;
249 AcpiGbl_GlobalList
->CurrentTotalSize
+= (UINT32
) Size
;
250 if (AcpiGbl_GlobalList
->CurrentTotalSize
> AcpiGbl_GlobalList
->MaxOccupied
)
252 AcpiGbl_GlobalList
->MaxOccupied
= AcpiGbl_GlobalList
->CurrentTotalSize
;
255 return ((void *) &Allocation
->UserSpace
);
259 /*******************************************************************************
261 * FUNCTION: AcpiUtFreeAndTrack
263 * PARAMETERS: Allocation - Address of the memory to deallocate
264 * Component - Component type of caller
265 * Module - Source file name of caller
266 * Line - Line number of caller
270 * DESCRIPTION: Frees the memory at Allocation
272 ******************************************************************************/
281 ACPI_DEBUG_MEM_BLOCK
*DebugBlock
;
285 ACPI_FUNCTION_TRACE_PTR (UtFree
, Allocation
);
288 if (NULL
== Allocation
)
290 ACPI_ERROR ((Module
, Line
,
291 "Attempt to delete a NULL address"));
296 DebugBlock
= ACPI_CAST_PTR (ACPI_DEBUG_MEM_BLOCK
,
297 (((char *) Allocation
) - sizeof (ACPI_DEBUG_MEM_HEADER
)));
299 AcpiGbl_GlobalList
->TotalFreed
++;
300 AcpiGbl_GlobalList
->CurrentTotalSize
-= DebugBlock
->Size
;
302 Status
= AcpiUtRemoveAllocation (DebugBlock
,
303 Component
, Module
, Line
);
304 if (ACPI_FAILURE (Status
))
306 ACPI_EXCEPTION ((AE_INFO
, Status
, "Could not free memory"));
309 AcpiOsFree (DebugBlock
);
310 ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS
, "%p freed\n", Allocation
));
315 /*******************************************************************************
317 * FUNCTION: AcpiUtFindAllocation
319 * PARAMETERS: Allocation - Address of allocated memory
321 * RETURN: Three cases:
322 * 1) List is empty, NULL is returned.
323 * 2) Element was found. Returns Allocation parameter.
324 * 3) Element was not found. Returns position where it should be
325 * inserted into the list.
327 * DESCRIPTION: Searches for an element in the global allocation tracking list.
328 * If the element is not found, returns the location within the
329 * list where the element should be inserted.
331 * Note: The list is ordered by larger-to-smaller addresses.
333 * This global list is used to detect memory leaks in ACPICA as
334 * well as other issues such as an attempt to release the same
335 * internal object more than once. Although expensive as far
336 * as cpu time, this list is much more helpful for finding these
337 * types of issues than using memory leak detectors outside of
340 ******************************************************************************/
342 static ACPI_DEBUG_MEM_BLOCK
*
343 AcpiUtFindAllocation (
344 ACPI_DEBUG_MEM_BLOCK
*Allocation
)
346 ACPI_DEBUG_MEM_BLOCK
*Element
;
349 Element
= AcpiGbl_GlobalList
->ListHead
;
356 * Search for the address.
358 * Note: List is ordered by larger-to-smaller addresses, on the
359 * assumption that a new allocation usually has a larger address
360 * than previous allocations.
362 while (Element
> Allocation
)
364 /* Check for end-of-list */
371 Element
= Element
->Next
;
374 if (Element
== Allocation
)
379 return (Element
->Previous
);
383 /*******************************************************************************
385 * FUNCTION: AcpiUtTrackAllocation
387 * PARAMETERS: Allocation - Address of allocated memory
388 * Size - Size of the allocation
389 * AllocType - MEM_MALLOC or MEM_CALLOC
390 * Component - Component type of caller
391 * Module - Source file name of caller
392 * Line - Line number of caller
396 * DESCRIPTION: Inserts an element into the global allocation tracking list.
398 ******************************************************************************/
401 AcpiUtTrackAllocation (
402 ACPI_DEBUG_MEM_BLOCK
*Allocation
,
409 ACPI_MEMORY_LIST
*MemList
;
410 ACPI_DEBUG_MEM_BLOCK
*Element
;
411 ACPI_STATUS Status
= AE_OK
;
414 ACPI_FUNCTION_TRACE_PTR (UtTrackAllocation
, Allocation
);
417 if (AcpiGbl_DisableMemTracking
)
419 return_ACPI_STATUS (AE_OK
);
422 MemList
= AcpiGbl_GlobalList
;
423 Status
= AcpiUtAcquireMutex (ACPI_MTX_MEMORY
);
424 if (ACPI_FAILURE (Status
))
426 return_ACPI_STATUS (Status
);
430 * Search the global list for this address to make sure it is not
431 * already present. This will catch several kinds of problems.
433 Element
= AcpiUtFindAllocation (Allocation
);
434 if (Element
== Allocation
)
436 ACPI_ERROR ((AE_INFO
,
437 "UtTrackAllocation: Allocation (%p) already present in global list!",
442 /* Fill in the instance data */
444 Allocation
->Size
= (UINT32
) Size
;
445 Allocation
->AllocType
= AllocType
;
446 Allocation
->Component
= Component
;
447 Allocation
->Line
= Line
;
449 ACPI_STRNCPY (Allocation
->Module
, Module
, ACPI_MAX_MODULE_NAME
);
450 Allocation
->Module
[ACPI_MAX_MODULE_NAME
-1] = 0;
454 /* Insert at list head */
456 if (MemList
->ListHead
)
458 ((ACPI_DEBUG_MEM_BLOCK
*)(MemList
->ListHead
))->Previous
= Allocation
;
461 Allocation
->Next
= MemList
->ListHead
;
462 Allocation
->Previous
= NULL
;
464 MemList
->ListHead
= Allocation
;
468 /* Insert after element */
470 Allocation
->Next
= Element
->Next
;
471 Allocation
->Previous
= Element
;
475 (Element
->Next
)->Previous
= Allocation
;
478 Element
->Next
= Allocation
;
483 Status
= AcpiUtReleaseMutex (ACPI_MTX_MEMORY
);
484 return_ACPI_STATUS (Status
);
488 /*******************************************************************************
490 * FUNCTION: AcpiUtRemoveAllocation
492 * PARAMETERS: Allocation - Address of allocated memory
493 * Component - Component type of caller
494 * Module - Source file name of caller
495 * Line - Line number of caller
499 * DESCRIPTION: Deletes an element from the global allocation tracking list.
501 ******************************************************************************/
504 AcpiUtRemoveAllocation (
505 ACPI_DEBUG_MEM_BLOCK
*Allocation
,
510 ACPI_MEMORY_LIST
*MemList
;
514 ACPI_FUNCTION_NAME (UtRemoveAllocation
);
517 if (AcpiGbl_DisableMemTracking
)
522 MemList
= AcpiGbl_GlobalList
;
523 if (NULL
== MemList
->ListHead
)
525 /* No allocations! */
527 ACPI_ERROR ((Module
, Line
,
528 "Empty allocation list, nothing to free!"));
533 Status
= AcpiUtAcquireMutex (ACPI_MTX_MEMORY
);
534 if (ACPI_FAILURE (Status
))
541 if (Allocation
->Previous
)
543 (Allocation
->Previous
)->Next
= Allocation
->Next
;
547 MemList
->ListHead
= Allocation
->Next
;
550 if (Allocation
->Next
)
552 (Allocation
->Next
)->Previous
= Allocation
->Previous
;
555 ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS
, "Freeing %p, size 0%X\n",
556 &Allocation
->UserSpace
, Allocation
->Size
));
558 /* Mark the segment as deleted */
560 ACPI_MEMSET (&Allocation
->UserSpace
, 0xEA, Allocation
->Size
);
562 Status
= AcpiUtReleaseMutex (ACPI_MTX_MEMORY
);
567 /*******************************************************************************
569 * FUNCTION: AcpiUtDumpAllocationInfo
575 * DESCRIPTION: Print some info about the outstanding allocations.
577 ******************************************************************************/
580 AcpiUtDumpAllocationInfo (
584 ACPI_MEMORY_LIST *MemList;
587 ACPI_FUNCTION_TRACE (UtDumpAllocationInfo
);
590 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
591 ("%30s: %4d (%3d Kb)\n", "Current allocations",
592 MemList->CurrentCount,
593 ROUND_UP_TO_1K (MemList->CurrentSize)));
595 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
596 ("%30s: %4d (%3d Kb)\n", "Max concurrent allocations",
597 MemList->MaxConcurrentCount,
598 ROUND_UP_TO_1K (MemList->MaxConcurrentSize)));
601 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
602 ("%30s: %4d (%3d Kb)\n", "Total (all) internal objects",
604 ROUND_UP_TO_1K (RunningObjectSize)));
606 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
607 ("%30s: %4d (%3d Kb)\n", "Total (all) allocations",
609 ROUND_UP_TO_1K (RunningAllocSize)));
612 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
613 ("%30s: %4d (%3d Kb)\n", "Current Nodes",
614 AcpiGbl_CurrentNodeCount,
615 ROUND_UP_TO_1K (AcpiGbl_CurrentNodeSize)));
617 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
618 ("%30s: %4d (%3d Kb)\n", "Max Nodes",
619 AcpiGbl_MaxConcurrentNodeCount,
620 ROUND_UP_TO_1K ((AcpiGbl_MaxConcurrentNodeCount *
621 sizeof (ACPI_NAMESPACE_NODE)))));
627 /*******************************************************************************
629 * FUNCTION: AcpiUtDumpAllocations
631 * PARAMETERS: Component - Component(s) to dump info for.
632 * Module - Module to dump info for. NULL means all.
636 * DESCRIPTION: Print a list of all outstanding allocations.
638 ******************************************************************************/
641 AcpiUtDumpAllocations (
645 ACPI_DEBUG_MEM_BLOCK
*Element
;
646 ACPI_DESCRIPTOR
*Descriptor
;
647 UINT32 NumOutstanding
= 0;
648 UINT8 DescriptorType
;
651 ACPI_FUNCTION_TRACE (UtDumpAllocations
);
654 if (AcpiGbl_DisableMemTracking
)
660 * Walk the allocation list.
662 if (ACPI_FAILURE (AcpiUtAcquireMutex (ACPI_MTX_MEMORY
)))
667 Element
= AcpiGbl_GlobalList
->ListHead
;
670 if ((Element
->Component
& Component
) &&
671 ((Module
== NULL
) || (0 == ACPI_STRCMP (Module
, Element
->Module
))))
673 Descriptor
= ACPI_CAST_PTR (ACPI_DESCRIPTOR
, &Element
->UserSpace
);
675 if (Element
->Size
< sizeof (ACPI_COMMON_DESCRIPTOR
))
677 AcpiOsPrintf ("%p Length 0x%04X %9.9s-%u "
678 "[Not a Descriptor - too small]\n",
679 Descriptor
, Element
->Size
, Element
->Module
,
684 /* Ignore allocated objects that are in a cache */
686 if (ACPI_GET_DESCRIPTOR_TYPE (Descriptor
) != ACPI_DESC_TYPE_CACHED
)
688 AcpiOsPrintf ("%p Length 0x%04X %9.9s-%u [%s] ",
689 Descriptor
, Element
->Size
, Element
->Module
,
690 Element
->Line
, AcpiUtGetDescriptorName (Descriptor
));
692 /* Validate the descriptor type using Type field and length */
694 DescriptorType
= 0; /* Not a valid descriptor type */
696 switch (ACPI_GET_DESCRIPTOR_TYPE (Descriptor
))
698 case ACPI_DESC_TYPE_OPERAND
:
700 if (Element
->Size
== sizeof (ACPI_OPERAND_OBJECT
))
702 DescriptorType
= ACPI_DESC_TYPE_OPERAND
;
706 case ACPI_DESC_TYPE_PARSER
:
708 if (Element
->Size
== sizeof (ACPI_PARSE_OBJECT
))
710 DescriptorType
= ACPI_DESC_TYPE_PARSER
;
714 case ACPI_DESC_TYPE_NAMED
:
716 if (Element
->Size
== sizeof (ACPI_NAMESPACE_NODE
))
718 DescriptorType
= ACPI_DESC_TYPE_NAMED
;
727 /* Display additional info for the major descriptor types */
729 switch (DescriptorType
)
731 case ACPI_DESC_TYPE_OPERAND
:
733 AcpiOsPrintf ("%12.12s RefCount 0x%04X\n",
734 AcpiUtGetTypeName (Descriptor
->Object
.Common
.Type
),
735 Descriptor
->Object
.Common
.ReferenceCount
);
738 case ACPI_DESC_TYPE_PARSER
:
740 AcpiOsPrintf ("AmlOpcode 0x%04hX\n",
741 Descriptor
->Op
.Asl
.AmlOpcode
);
744 case ACPI_DESC_TYPE_NAMED
:
746 AcpiOsPrintf ("%4.4s\n",
747 AcpiUtGetNodeName (&Descriptor
->Node
));
752 AcpiOsPrintf ( "\n");
761 Element
= Element
->Next
;
764 (void) AcpiUtReleaseMutex (ACPI_MTX_MEMORY
);
770 ACPI_INFO ((AE_INFO
, "No outstanding allocations"));
774 ACPI_ERROR ((AE_INFO
, "%u(0x%X) Outstanding allocations",
775 NumOutstanding
, NumOutstanding
));
781 #endif /* ACPI_DBG_TRACK_ALLOCATIONS */