1 /******************************************************************************
2  *
3  * Module Name: uttrack - Memory allocation tracking routines (debug only)
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
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.
25  *
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.
29  *
30  * NO WARRANTY
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.
42  */
43 
44 /*
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.
47  *
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.
53  */
54 
55 #include "acpi.h"
56 #include "accommon.h"
57 
58 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
59 
60 #define _COMPONENT          ACPI_UTILITIES
61         ACPI_MODULE_NAME    ("uttrack")
62 
63 
64 /* Local prototypes */
65 
66 static ACPI_DEBUG_MEM_BLOCK *
67 AcpiUtFindAllocation (
68     ACPI_DEBUG_MEM_BLOCK    *Allocation);
69 
70 static ACPI_STATUS
71 AcpiUtTrackAllocation (
72     ACPI_DEBUG_MEM_BLOCK    *Address,
73     ACPI_SIZE               Size,
74     UINT8                   AllocType,
75     UINT32                  Component,
76     const char              *Module,
77     UINT32                  Line);
78 
79 static ACPI_STATUS
80 AcpiUtRemoveAllocation (
81     ACPI_DEBUG_MEM_BLOCK    *Address,
82     UINT32                  Component,
83     const char              *Module,
84     UINT32                  Line);
85 
86 
87 /*******************************************************************************
88  *
89  * FUNCTION:    AcpiUtCreateList
90  *
91  * PARAMETERS:  CacheName       - Ascii name for the cache
92  *              ObjectSize      - Size of each cached object
93  *              ReturnCache     - Where the new cache object is returned
94  *
95  * RETURN:      Status
96  *
97  * DESCRIPTION: Create a local memory list for tracking purposed
98  *
99  ******************************************************************************/
100 
101 ACPI_STATUS
102 AcpiUtCreateList (
103     const char              *ListName,
104     UINT16                  ObjectSize,
105     ACPI_MEMORY_LIST        **ReturnCache)
106 {
107     ACPI_MEMORY_LIST        *Cache;
108 
109 
110     Cache = AcpiOsAllocateZeroed (sizeof (ACPI_MEMORY_LIST));
111     if (!Cache)
112     {
113         return (AE_NO_MEMORY);
114     }
115 
116     Cache->ListName = ListName;
117     Cache->ObjectSize = ObjectSize;
118 
119     *ReturnCache = Cache;
120     return (AE_OK);
121 }
122 
123 
124 /*******************************************************************************
125  *
126  * FUNCTION:    AcpiUtAllocateAndTrack
127  *
128  * PARAMETERS:  Size                - Size of the allocation
129  *              Component           - Component type of caller
130  *              Module              - Source file name of caller
131  *              Line                - Line number of caller
132  *
133  * RETURN:      Address of the allocated memory on success, NULL on failure.
134  *
135  * DESCRIPTION: The subsystem's equivalent of malloc.
136  *
137  ******************************************************************************/
138 
139 void *
140 AcpiUtAllocateAndTrack (
141     ACPI_SIZE               Size,
142     UINT32                  Component,
143     const char              *Module,
144     UINT32                  Line)
145 {
146     ACPI_DEBUG_MEM_BLOCK    *Allocation;
147     ACPI_STATUS             Status;
148 
149 
150     /* Check for an inadvertent size of zero bytes */
151 
152     if (!Size)
153     {
154         ACPI_WARNING ((Module, Line,
155             "Attempt to allocate zero bytes, allocating 1 byte"));
156         Size = 1;
157     }
158 
159     Allocation = AcpiOsAllocate (Size + sizeof (ACPI_DEBUG_MEM_HEADER));
160     if (!Allocation)
161     {
162         /* Report allocation error */
163 
164         ACPI_WARNING ((Module, Line,
165             "Could not allocate size %u", (UINT32) Size));
166 
167         return (NULL);
168     }
169 
170     Status = AcpiUtTrackAllocation (
171         Allocation, Size, ACPI_MEM_MALLOC, Component, Module, Line);
172     if (ACPI_FAILURE (Status))
173     {
174         AcpiOsFree (Allocation);
175         return (NULL);
176     }
177 
178     AcpiGbl_GlobalList->TotalAllocated++;
179     AcpiGbl_GlobalList->TotalSize += (UINT32) Size;
180     AcpiGbl_GlobalList->CurrentTotalSize += (UINT32) Size;
181 
182     if (AcpiGbl_GlobalList->CurrentTotalSize >
183         AcpiGbl_GlobalList->MaxOccupied)
184     {
185         AcpiGbl_GlobalList->MaxOccupied =
186             AcpiGbl_GlobalList->CurrentTotalSize;
187     }
188 
189     return ((void *) &Allocation->UserSpace);
190 }
191 
192 
193 /*******************************************************************************
194  *
195  * FUNCTION:    AcpiUtAllocateZeroedAndTrack
196  *
197  * PARAMETERS:  Size                - Size of the allocation
198  *              Component           - Component type of caller
199  *              Module              - Source file name of caller
200  *              Line                - Line number of caller
201  *
202  * RETURN:      Address of the allocated memory on success, NULL on failure.
203  *
204  * DESCRIPTION: Subsystem equivalent of calloc.
205  *
206  ******************************************************************************/
207 
208 void *
209 AcpiUtAllocateZeroedAndTrack (
210     ACPI_SIZE               Size,
211     UINT32                  Component,
212     const char              *Module,
213     UINT32                  Line)
214 {
215     ACPI_DEBUG_MEM_BLOCK    *Allocation;
216     ACPI_STATUS             Status;
217 
218 
219     /* Check for an inadvertent size of zero bytes */
220 
221     if (!Size)
222     {
223         ACPI_WARNING ((Module, Line,
224             "Attempt to allocate zero bytes, allocating 1 byte"));
225         Size = 1;
226     }
227 
228     Allocation = AcpiOsAllocateZeroed (
229         Size + sizeof (ACPI_DEBUG_MEM_HEADER));
230     if (!Allocation)
231     {
232         /* Report allocation error */
233 
234         ACPI_ERROR ((Module, Line,
235             "Could not allocate size %u", (UINT32) Size));
236         return (NULL);
237     }
238 
239     Status = AcpiUtTrackAllocation (Allocation, Size,
240         ACPI_MEM_CALLOC, Component, Module, Line);
241     if (ACPI_FAILURE (Status))
242     {
243         AcpiOsFree (Allocation);
244         return (NULL);
245     }
246 
247     AcpiGbl_GlobalList->TotalAllocated++;
248     AcpiGbl_GlobalList->TotalSize += (UINT32) Size;
249     AcpiGbl_GlobalList->CurrentTotalSize += (UINT32) Size;
250 
251     if (AcpiGbl_GlobalList->CurrentTotalSize >
252         AcpiGbl_GlobalList->MaxOccupied)
253     {
254         AcpiGbl_GlobalList->MaxOccupied =
255             AcpiGbl_GlobalList->CurrentTotalSize;
256     }
257 
258     return ((void *) &Allocation->UserSpace);
259 }
260 
261 
262 /*******************************************************************************
263  *
264  * FUNCTION:    AcpiUtFreeAndTrack
265  *
266  * PARAMETERS:  Allocation          - Address of the memory to deallocate
267  *              Component           - Component type of caller
268  *              Module              - Source file name of caller
269  *              Line                - Line number of caller
270  *
271  * RETURN:      None
272  *
273  * DESCRIPTION: Frees the memory at Allocation
274  *
275  ******************************************************************************/
276 
277 void
278 AcpiUtFreeAndTrack (
279     void                    *Allocation,
280     UINT32                  Component,
281     const char              *Module,
282     UINT32                  Line)
283 {
284     ACPI_DEBUG_MEM_BLOCK    *DebugBlock;
285     ACPI_STATUS             Status;
286 
287 
288     ACPI_FUNCTION_TRACE_PTR (UtFree, Allocation);
289 
290 
291     if (NULL == Allocation)
292     {
293         ACPI_ERROR ((Module, Line,
294             "Attempt to delete a NULL address"));
295 
296         return_VOID;
297     }
298 
299     DebugBlock = ACPI_CAST_PTR (ACPI_DEBUG_MEM_BLOCK,
300         (((char *) Allocation) - sizeof (ACPI_DEBUG_MEM_HEADER)));
301 
302     AcpiGbl_GlobalList->TotalFreed++;
303     AcpiGbl_GlobalList->CurrentTotalSize -= DebugBlock->Size;
304 
305     Status = AcpiUtRemoveAllocation (DebugBlock, Component, Module, Line);
306     if (ACPI_FAILURE (Status))
307     {
308         ACPI_EXCEPTION ((AE_INFO, Status, "Could not free memory"));
309     }
310 
311     AcpiOsFree (DebugBlock);
312     ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "%p freed (block %p)\n",
313         Allocation, DebugBlock));
314     return_VOID;
315 }
316 
317 
318 /*******************************************************************************
319  *
320  * FUNCTION:    AcpiUtFindAllocation
321  *
322  * PARAMETERS:  Allocation              - Address of allocated memory
323  *
324  * RETURN:      Three cases:
325  *              1) List is empty, NULL is returned.
326  *              2) Element was found. Returns Allocation parameter.
327  *              3) Element was not found. Returns position where it should be
328  *                  inserted into the list.
329  *
330  * DESCRIPTION: Searches for an element in the global allocation tracking list.
331  *              If the element is not found, returns the location within the
332  *              list where the element should be inserted.
333  *
334  *              Note: The list is ordered by larger-to-smaller addresses.
335  *
336  *              This global list is used to detect memory leaks in ACPICA as
337  *              well as other issues such as an attempt to release the same
338  *              internal object more than once. Although expensive as far
339  *              as cpu time, this list is much more helpful for finding these
340  *              types of issues than using memory leak detectors outside of
341  *              the ACPICA code.
342  *
343  ******************************************************************************/
344 
345 static ACPI_DEBUG_MEM_BLOCK *
346 AcpiUtFindAllocation (
347     ACPI_DEBUG_MEM_BLOCK    *Allocation)
348 {
349     ACPI_DEBUG_MEM_BLOCK    *Element;
350 
351 
352     Element = AcpiGbl_GlobalList->ListHead;
353     if (!Element)
354     {
355         return (NULL);
356     }
357 
358     /*
359      * Search for the address.
360      *
361      * Note: List is ordered by larger-to-smaller addresses, on the
362      * assumption that a new allocation usually has a larger address
363      * than previous allocations.
364      */
365     while (Element > Allocation)
366     {
367         /* Check for end-of-list */
368 
369         if (!Element->Next)
370         {
371             return (Element);
372         }
373 
374         Element = Element->Next;
375     }
376 
377     if (Element == Allocation)
378     {
379         return (Element);
380     }
381 
382     return (Element->Previous);
383 }
384 
385 
386 /*******************************************************************************
387  *
388  * FUNCTION:    AcpiUtTrackAllocation
389  *
390  * PARAMETERS:  Allocation          - Address of allocated memory
391  *              Size                - Size of the allocation
392  *              AllocType           - MEM_MALLOC or MEM_CALLOC
393  *              Component           - Component type of caller
394  *              Module              - Source file name of caller
395  *              Line                - Line number of caller
396  *
397  * RETURN:      Status
398  *
399  * DESCRIPTION: Inserts an element into the global allocation tracking list.
400  *
401  ******************************************************************************/
402 
403 static ACPI_STATUS
404 AcpiUtTrackAllocation (
405     ACPI_DEBUG_MEM_BLOCK    *Allocation,
406     ACPI_SIZE               Size,
407     UINT8                   AllocType,
408     UINT32                  Component,
409     const char              *Module,
410     UINT32                  Line)
411 {
412     ACPI_MEMORY_LIST        *MemList;
413     ACPI_DEBUG_MEM_BLOCK    *Element;
414     ACPI_STATUS             Status = AE_OK;
415 
416 
417     ACPI_FUNCTION_TRACE_PTR (UtTrackAllocation, Allocation);
418 
419 
420     if (AcpiGbl_DisableMemTracking)
421     {
422         return_ACPI_STATUS (AE_OK);
423     }
424 
425     MemList = AcpiGbl_GlobalList;
426     Status = AcpiUtAcquireMutex (ACPI_MTX_MEMORY);
427     if (ACPI_FAILURE (Status))
428     {
429         return_ACPI_STATUS (Status);
430     }
431 
432     /*
433      * Search the global list for this address to make sure it is not
434      * already present. This will catch several kinds of problems.
435      */
436     Element = AcpiUtFindAllocation (Allocation);
437     if (Element == Allocation)
438     {
439         ACPI_ERROR ((AE_INFO,
440             "UtTrackAllocation: Allocation (%p) already present in global list!",
441             Allocation));
442         goto UnlockAndExit;
443     }
444 
445     /* Fill in the instance data */
446 
447     Allocation->Size = (UINT32) Size;
448     Allocation->AllocType = AllocType;
449     Allocation->Component = Component;
450     Allocation->Line = Line;
451 
452     strncpy (Allocation->Module, Module, ACPI_MAX_MODULE_NAME);
453     Allocation->Module[ACPI_MAX_MODULE_NAME-1] = 0;
454 
455     if (!Element)
456     {
457         /* Insert at list head */
458 
459         if (MemList->ListHead)
460         {
461             ((ACPI_DEBUG_MEM_BLOCK *)(MemList->ListHead))->Previous =
462                 Allocation;
463         }
464 
465         Allocation->Next = MemList->ListHead;
466         Allocation->Previous = NULL;
467 
468         MemList->ListHead = Allocation;
469     }
470     else
471     {
472         /* Insert after element */
473 
474         Allocation->Next = Element->Next;
475         Allocation->Previous = Element;
476 
477         if (Element->Next)
478         {
479             (Element->Next)->Previous = Allocation;
480         }
481 
482         Element->Next = Allocation;
483     }
484 
485 
486 UnlockAndExit:
487     Status = AcpiUtReleaseMutex (ACPI_MTX_MEMORY);
488     return_ACPI_STATUS (Status);
489 }
490 
491 
492 /*******************************************************************************
493  *
494  * FUNCTION:    AcpiUtRemoveAllocation
495  *
496  * PARAMETERS:  Allocation          - Address of allocated memory
497  *              Component           - Component type of caller
498  *              Module              - Source file name of caller
499  *              Line                - Line number of caller
500  *
501  * RETURN:      Status
502  *
503  * DESCRIPTION: Deletes an element from the global allocation tracking list.
504  *
505  ******************************************************************************/
506 
507 static ACPI_STATUS
508 AcpiUtRemoveAllocation (
509     ACPI_DEBUG_MEM_BLOCK    *Allocation,
510     UINT32                  Component,
511     const char              *Module,
512     UINT32                  Line)
513 {
514     ACPI_MEMORY_LIST        *MemList;
515     ACPI_STATUS             Status;
516 
517 
518     ACPI_FUNCTION_NAME (UtRemoveAllocation);
519 
520 
521     if (AcpiGbl_DisableMemTracking)
522     {
523         return (AE_OK);
524     }
525 
526     MemList = AcpiGbl_GlobalList;
527     if (NULL == MemList->ListHead)
528     {
529         /* No allocations! */
530 
531         ACPI_ERROR ((Module, Line,
532             "Empty allocation list, nothing to free!"));
533 
534         return (AE_OK);
535     }
536 
537     Status = AcpiUtAcquireMutex (ACPI_MTX_MEMORY);
538     if (ACPI_FAILURE (Status))
539     {
540         return (Status);
541     }
542 
543     /* Unlink */
544 
545     if (Allocation->Previous)
546     {
547         (Allocation->Previous)->Next = Allocation->Next;
548     }
549     else
550     {
551         MemList->ListHead = Allocation->Next;
552     }
553 
554     if (Allocation->Next)
555     {
556         (Allocation->Next)->Previous = Allocation->Previous;
557     }
558 
559     ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Freeing %p, size 0%X\n",
560         &Allocation->UserSpace, Allocation->Size));
561 
562     /* Mark the segment as deleted */
563 
564     memset (&Allocation->UserSpace, 0xEA, Allocation->Size);
565 
566     Status = AcpiUtReleaseMutex (ACPI_MTX_MEMORY);
567     return (Status);
568 }
569 
570 
571 /*******************************************************************************
572  *
573  * FUNCTION:    AcpiUtDumpAllocationInfo
574  *
575  * PARAMETERS:  None
576  *
577  * RETURN:      None
578  *
579  * DESCRIPTION: Print some info about the outstanding allocations.
580  *
581  ******************************************************************************/
582 
583 void
584 AcpiUtDumpAllocationInfo (
585     void)
586 {
587 /*
588     ACPI_MEMORY_LIST        *MemList;
589 */
590 
591     ACPI_FUNCTION_TRACE (UtDumpAllocationInfo);
592 
593 /*
594     ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
595         ("%30s: %4d (%3d Kb)\n", "Current allocations",
596         MemList->CurrentCount,
597         ROUND_UP_TO_1K (MemList->CurrentSize)));
598 
599     ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
600         ("%30s: %4d (%3d Kb)\n", "Max concurrent allocations",
601         MemList->MaxConcurrentCount,
602         ROUND_UP_TO_1K (MemList->MaxConcurrentSize)));
603 
604 
605     ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
606         ("%30s: %4d (%3d Kb)\n", "Total (all) internal objects",
607         RunningObjectCount,
608         ROUND_UP_TO_1K (RunningObjectSize)));
609 
610     ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
611         ("%30s: %4d (%3d Kb)\n", "Total (all) allocations",
612         RunningAllocCount,
613         ROUND_UP_TO_1K (RunningAllocSize)));
614 
615 
616     ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
617         ("%30s: %4d (%3d Kb)\n", "Current Nodes",
618         AcpiGbl_CurrentNodeCount,
619         ROUND_UP_TO_1K (AcpiGbl_CurrentNodeSize)));
620 
621     ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
622         ("%30s: %4d (%3d Kb)\n", "Max Nodes",
623         AcpiGbl_MaxConcurrentNodeCount,
624         ROUND_UP_TO_1K ((AcpiGbl_MaxConcurrentNodeCount *
625             sizeof (ACPI_NAMESPACE_NODE)))));
626 */
627     return_VOID;
628 }
629 
630 
631 /*******************************************************************************
632  *
633  * FUNCTION:    AcpiUtDumpAllocations
634  *
635  * PARAMETERS:  Component           - Component(s) to dump info for.
636  *              Module              - Module to dump info for. NULL means all.
637  *
638  * RETURN:      None
639  *
640  * DESCRIPTION: Print a list of all outstanding allocations.
641  *
642  ******************************************************************************/
643 
644 void
645 AcpiUtDumpAllocations (
646     UINT32                  Component,
647     const char              *Module)
648 {
649     ACPI_DEBUG_MEM_BLOCK    *Element;
650     ACPI_DESCRIPTOR         *Descriptor;
651     UINT32                  NumOutstanding = 0;
652     UINT8                   DescriptorType;
653 
654 
655     ACPI_FUNCTION_TRACE (UtDumpAllocations);
656 
657 
658     if (AcpiGbl_DisableMemTracking)
659     {
660         return_VOID;
661     }
662 
663     /*
664      * Walk the allocation list.
665      */
666     if (ACPI_FAILURE (AcpiUtAcquireMutex (ACPI_MTX_MEMORY)))
667     {
668         return_VOID;
669     }
670 
671     Element = AcpiGbl_GlobalList->ListHead;
672     while (Element)
673     {
674         if ((Element->Component & Component) &&
675             ((Module == NULL) || (0 == strcmp (Module, Element->Module))))
676         {
677             Descriptor = ACPI_CAST_PTR (
678                 ACPI_DESCRIPTOR, &Element->UserSpace);
679 
680             if (Element->Size < sizeof (ACPI_COMMON_DESCRIPTOR))
681             {
682                 AcpiOsPrintf ("%p Length 0x%04X %9.9s-%u "
683                     "[Not a Descriptor - too small]\n",
684                     Descriptor, Element->Size, Element->Module,
685                     Element->Line);
686             }
687             else
688             {
689                 /* Ignore allocated objects that are in a cache */
690 
691                 if (ACPI_GET_DESCRIPTOR_TYPE (Descriptor) !=
692                     ACPI_DESC_TYPE_CACHED)
693                 {
694                     AcpiOsPrintf ("%p Length 0x%04X %9.9s-%u [%s] ",
695                         Descriptor, Element->Size, Element->Module,
696                         Element->Line, AcpiUtGetDescriptorName (Descriptor));
697 
698                     /* Validate the descriptor type using Type field and length */
699 
700                     DescriptorType = 0; /* Not a valid descriptor type */
701 
702                     switch (ACPI_GET_DESCRIPTOR_TYPE (Descriptor))
703                     {
704                     case ACPI_DESC_TYPE_OPERAND:
705 
706                         if (Element->Size == sizeof (ACPI_OPERAND_OBJECT))
707                         {
708                             DescriptorType = ACPI_DESC_TYPE_OPERAND;
709                         }
710                         break;
711 
712                     case ACPI_DESC_TYPE_PARSER:
713 
714                         if (Element->Size == sizeof (ACPI_PARSE_OBJECT))
715                         {
716                             DescriptorType = ACPI_DESC_TYPE_PARSER;
717                         }
718                         break;
719 
720                     case ACPI_DESC_TYPE_NAMED:
721 
722                         if (Element->Size == sizeof (ACPI_NAMESPACE_NODE))
723                         {
724                             DescriptorType = ACPI_DESC_TYPE_NAMED;
725                         }
726                         break;
727 
728                     default:
729 
730                         break;
731                     }
732 
733                     /* Display additional info for the major descriptor types */
734 
735                     switch (DescriptorType)
736                     {
737                     case ACPI_DESC_TYPE_OPERAND:
738 
739                         AcpiOsPrintf ("%12.12s  RefCount 0x%04X\n",
740                             AcpiUtGetTypeName (Descriptor->Object.Common.Type),
741                             Descriptor->Object.Common.ReferenceCount);
742                         break;
743 
744                     case ACPI_DESC_TYPE_PARSER:
745 
746                         AcpiOsPrintf ("AmlOpcode 0x%04hX\n",
747                             Descriptor->Op.Asl.AmlOpcode);
748                         break;
749 
750                     case ACPI_DESC_TYPE_NAMED:
751 
752                         AcpiOsPrintf ("%4.4s\n",
753                             AcpiUtGetNodeName (&Descriptor->Node));
754                         break;
755 
756                     default:
757 
758                         AcpiOsPrintf ( "\n");
759                         break;
760                     }
761                 }
762             }
763 
764             NumOutstanding++;
765         }
766 
767         Element = Element->Next;
768     }
769 
770     (void) AcpiUtReleaseMutex (ACPI_MTX_MEMORY);
771 
772     /* Print summary */
773 
774     if (!NumOutstanding)
775     {
776         ACPI_INFO (("No outstanding allocations"));
777     }
778     else
779     {
780         ACPI_ERROR ((AE_INFO, "%u(0x%X) Outstanding allocations",
781             NumOutstanding, NumOutstanding));
782     }
783 
784     return_VOID;
785 }
786 
787 #endif  /* ACPI_DBG_TRACK_ALLOCATIONS */
788