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