Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /******************************************************************************
0003  *
0004  * Module Name: uttrack - Memory allocation tracking routines (debug only)
0005  *
0006  * Copyright (C) 2000 - 2022, Intel Corp.
0007  *
0008  *****************************************************************************/
0009 
0010 /*
0011  * These procedures are used for tracking memory leaks in the subsystem, and
0012  * they get compiled out when the ACPI_DBG_TRACK_ALLOCATIONS is not set.
0013  *
0014  * Each memory allocation is tracked via a doubly linked list. Each
0015  * element contains the caller's component, module name, function name, and
0016  * line number. acpi_ut_allocate and acpi_ut_allocate_zeroed call
0017  * acpi_ut_track_allocation to add an element to the list; deletion
0018  * occurs in the body of acpi_ut_free.
0019  */
0020 
0021 #include <acpi/acpi.h>
0022 #include "accommon.h"
0023 
0024 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
0025 
0026 #define _COMPONENT          ACPI_UTILITIES
0027 ACPI_MODULE_NAME("uttrack")
0028 
0029 /* Local prototypes */
0030 static struct acpi_debug_mem_block *acpi_ut_find_allocation(struct
0031                                 acpi_debug_mem_block
0032                                 *allocation);
0033 
0034 static acpi_status
0035 acpi_ut_track_allocation(struct acpi_debug_mem_block *address,
0036              acpi_size size,
0037              u8 alloc_type,
0038              u32 component, const char *module, u32 line);
0039 
0040 static acpi_status
0041 acpi_ut_remove_allocation(struct acpi_debug_mem_block *address,
0042               u32 component, const char *module, u32 line);
0043 
0044 /*******************************************************************************
0045  *
0046  * FUNCTION:    acpi_ut_create_list
0047  *
0048  * PARAMETERS:  cache_name      - Ascii name for the cache
0049  *              object_size     - Size of each cached object
0050  *              return_cache    - Where the new cache object is returned
0051  *
0052  * RETURN:      Status
0053  *
0054  * DESCRIPTION: Create a local memory list for tracking purposed
0055  *
0056  ******************************************************************************/
0057 
0058 acpi_status
0059 acpi_ut_create_list(const char *list_name,
0060             u16 object_size, struct acpi_memory_list **return_cache)
0061 {
0062     struct acpi_memory_list *cache;
0063 
0064     cache = acpi_os_allocate_zeroed(sizeof(struct acpi_memory_list));
0065     if (!cache) {
0066         return (AE_NO_MEMORY);
0067     }
0068 
0069     cache->list_name = list_name;
0070     cache->object_size = object_size;
0071 
0072     *return_cache = cache;
0073     return (AE_OK);
0074 }
0075 
0076 /*******************************************************************************
0077  *
0078  * FUNCTION:    acpi_ut_allocate_and_track
0079  *
0080  * PARAMETERS:  size                - Size of the allocation
0081  *              component           - Component type of caller
0082  *              module              - Source file name of caller
0083  *              line                - Line number of caller
0084  *
0085  * RETURN:      Address of the allocated memory on success, NULL on failure.
0086  *
0087  * DESCRIPTION: The subsystem's equivalent of malloc.
0088  *
0089  ******************************************************************************/
0090 
0091 void *acpi_ut_allocate_and_track(acpi_size size,
0092                  u32 component, const char *module, u32 line)
0093 {
0094     struct acpi_debug_mem_block *allocation;
0095     acpi_status status;
0096 
0097     /* Check for an inadvertent size of zero bytes */
0098 
0099     if (!size) {
0100         ACPI_WARNING((module, line,
0101                   "Attempt to allocate zero bytes, allocating 1 byte"));
0102         size = 1;
0103     }
0104 
0105     allocation =
0106         acpi_os_allocate(size + sizeof(struct acpi_debug_mem_header));
0107     if (!allocation) {
0108 
0109         /* Report allocation error */
0110 
0111         ACPI_WARNING((module, line,
0112                   "Could not allocate size %u", (u32)size));
0113 
0114         return (NULL);
0115     }
0116 
0117     status =
0118         acpi_ut_track_allocation(allocation, size, ACPI_MEM_MALLOC,
0119                      component, module, line);
0120     if (ACPI_FAILURE(status)) {
0121         acpi_os_free(allocation);
0122         return (NULL);
0123     }
0124 
0125     acpi_gbl_global_list->total_allocated++;
0126     acpi_gbl_global_list->total_size += (u32)size;
0127     acpi_gbl_global_list->current_total_size += (u32)size;
0128 
0129     if (acpi_gbl_global_list->current_total_size >
0130         acpi_gbl_global_list->max_occupied) {
0131         acpi_gbl_global_list->max_occupied =
0132             acpi_gbl_global_list->current_total_size;
0133     }
0134 
0135     return ((void *)&allocation->user_space);
0136 }
0137 
0138 /*******************************************************************************
0139  *
0140  * FUNCTION:    acpi_ut_allocate_zeroed_and_track
0141  *
0142  * PARAMETERS:  size                - Size of the allocation
0143  *              component           - Component type of caller
0144  *              module              - Source file name of caller
0145  *              line                - Line number of caller
0146  *
0147  * RETURN:      Address of the allocated memory on success, NULL on failure.
0148  *
0149  * DESCRIPTION: Subsystem equivalent of calloc.
0150  *
0151  ******************************************************************************/
0152 
0153 void *acpi_ut_allocate_zeroed_and_track(acpi_size size,
0154                     u32 component,
0155                     const char *module, u32 line)
0156 {
0157     struct acpi_debug_mem_block *allocation;
0158     acpi_status status;
0159 
0160     /* Check for an inadvertent size of zero bytes */
0161 
0162     if (!size) {
0163         ACPI_WARNING((module, line,
0164                   "Attempt to allocate zero bytes, allocating 1 byte"));
0165         size = 1;
0166     }
0167 
0168     allocation =
0169         acpi_os_allocate_zeroed(size +
0170                     sizeof(struct acpi_debug_mem_header));
0171     if (!allocation) {
0172 
0173         /* Report allocation error */
0174 
0175         ACPI_ERROR((module, line,
0176                 "Could not allocate size %u", (u32)size));
0177         return (NULL);
0178     }
0179 
0180     status = acpi_ut_track_allocation(allocation, size,
0181                       ACPI_MEM_CALLOC, component, module,
0182                       line);
0183     if (ACPI_FAILURE(status)) {
0184         acpi_os_free(allocation);
0185         return (NULL);
0186     }
0187 
0188     acpi_gbl_global_list->total_allocated++;
0189     acpi_gbl_global_list->total_size += (u32)size;
0190     acpi_gbl_global_list->current_total_size += (u32)size;
0191 
0192     if (acpi_gbl_global_list->current_total_size >
0193         acpi_gbl_global_list->max_occupied) {
0194         acpi_gbl_global_list->max_occupied =
0195             acpi_gbl_global_list->current_total_size;
0196     }
0197 
0198     return ((void *)&allocation->user_space);
0199 }
0200 
0201 /*******************************************************************************
0202  *
0203  * FUNCTION:    acpi_ut_free_and_track
0204  *
0205  * PARAMETERS:  allocation          - Address of the memory to deallocate
0206  *              component           - Component type of caller
0207  *              module              - Source file name of caller
0208  *              line                - Line number of caller
0209  *
0210  * RETURN:      None
0211  *
0212  * DESCRIPTION: Frees the memory at Allocation
0213  *
0214  ******************************************************************************/
0215 
0216 void
0217 acpi_ut_free_and_track(void *allocation,
0218                u32 component, const char *module, u32 line)
0219 {
0220     struct acpi_debug_mem_block *debug_block;
0221     acpi_status status;
0222 
0223     ACPI_FUNCTION_TRACE_PTR(ut_free, allocation);
0224 
0225     if (NULL == allocation) {
0226         ACPI_ERROR((module, line, "Attempt to delete a NULL address"));
0227 
0228         return_VOID;
0229     }
0230 
0231     debug_block = ACPI_CAST_PTR(struct acpi_debug_mem_block,
0232                     (((char *)allocation) -
0233                      sizeof(struct acpi_debug_mem_header)));
0234 
0235     acpi_gbl_global_list->total_freed++;
0236     acpi_gbl_global_list->current_total_size -= debug_block->size;
0237 
0238     status =
0239         acpi_ut_remove_allocation(debug_block, component, module, line);
0240     if (ACPI_FAILURE(status)) {
0241         ACPI_EXCEPTION((AE_INFO, status, "Could not free memory"));
0242     }
0243 
0244     acpi_os_free(debug_block);
0245     ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "%p freed (block %p)\n",
0246               allocation, debug_block));
0247     return_VOID;
0248 }
0249 
0250 /*******************************************************************************
0251  *
0252  * FUNCTION:    acpi_ut_find_allocation
0253  *
0254  * PARAMETERS:  allocation              - Address of allocated memory
0255  *
0256  * RETURN:      Three cases:
0257  *              1) List is empty, NULL is returned.
0258  *              2) Element was found. Returns Allocation parameter.
0259  *              3) Element was not found. Returns position where it should be
0260  *                  inserted into the list.
0261  *
0262  * DESCRIPTION: Searches for an element in the global allocation tracking list.
0263  *              If the element is not found, returns the location within the
0264  *              list where the element should be inserted.
0265  *
0266  *              Note: The list is ordered by larger-to-smaller addresses.
0267  *
0268  *              This global list is used to detect memory leaks in ACPICA as
0269  *              well as other issues such as an attempt to release the same
0270  *              internal object more than once. Although expensive as far
0271  *              as cpu time, this list is much more helpful for finding these
0272  *              types of issues than using memory leak detectors outside of
0273  *              the ACPICA code.
0274  *
0275  ******************************************************************************/
0276 
0277 static struct acpi_debug_mem_block *acpi_ut_find_allocation(struct
0278                                 acpi_debug_mem_block
0279                                 *allocation)
0280 {
0281     struct acpi_debug_mem_block *element;
0282 
0283     element = acpi_gbl_global_list->list_head;
0284     if (!element) {
0285         return (NULL);
0286     }
0287 
0288     /*
0289      * Search for the address.
0290      *
0291      * Note: List is ordered by larger-to-smaller addresses, on the
0292      * assumption that a new allocation usually has a larger address
0293      * than previous allocations.
0294      */
0295     while (element > allocation) {
0296 
0297         /* Check for end-of-list */
0298 
0299         if (!element->next) {
0300             return (element);
0301         }
0302 
0303         element = element->next;
0304     }
0305 
0306     if (element == allocation) {
0307         return (element);
0308     }
0309 
0310     return (element->previous);
0311 }
0312 
0313 /*******************************************************************************
0314  *
0315  * FUNCTION:    acpi_ut_track_allocation
0316  *
0317  * PARAMETERS:  allocation          - Address of allocated memory
0318  *              size                - Size of the allocation
0319  *              alloc_type          - MEM_MALLOC or MEM_CALLOC
0320  *              component           - Component type of caller
0321  *              module              - Source file name of caller
0322  *              line                - Line number of caller
0323  *
0324  * RETURN:      Status
0325  *
0326  * DESCRIPTION: Inserts an element into the global allocation tracking list.
0327  *
0328  ******************************************************************************/
0329 
0330 static acpi_status
0331 acpi_ut_track_allocation(struct acpi_debug_mem_block *allocation,
0332              acpi_size size,
0333              u8 alloc_type,
0334              u32 component, const char *module, u32 line)
0335 {
0336     struct acpi_memory_list *mem_list;
0337     struct acpi_debug_mem_block *element;
0338     acpi_status status = AE_OK;
0339 
0340     ACPI_FUNCTION_TRACE_PTR(ut_track_allocation, allocation);
0341 
0342     if (acpi_gbl_disable_mem_tracking) {
0343         return_ACPI_STATUS(AE_OK);
0344     }
0345 
0346     mem_list = acpi_gbl_global_list;
0347     status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY);
0348     if (ACPI_FAILURE(status)) {
0349         return_ACPI_STATUS(status);
0350     }
0351 
0352     /*
0353      * Search the global list for this address to make sure it is not
0354      * already present. This will catch several kinds of problems.
0355      */
0356     element = acpi_ut_find_allocation(allocation);
0357     if (element == allocation) {
0358         ACPI_ERROR((AE_INFO,
0359                 "UtTrackAllocation: Allocation (%p) already present in global list!",
0360                 allocation));
0361         goto unlock_and_exit;
0362     }
0363 
0364     /* Fill in the instance data */
0365 
0366     allocation->size = (u32)size;
0367     allocation->alloc_type = alloc_type;
0368     allocation->component = component;
0369     allocation->line = line;
0370 
0371     acpi_ut_safe_strncpy(allocation->module, (char *)module,
0372                  ACPI_MAX_MODULE_NAME);
0373 
0374     if (!element) {
0375 
0376         /* Insert at list head */
0377 
0378         if (mem_list->list_head) {
0379             ((struct acpi_debug_mem_block *)(mem_list->list_head))->
0380                 previous = allocation;
0381         }
0382 
0383         allocation->next = mem_list->list_head;
0384         allocation->previous = NULL;
0385 
0386         mem_list->list_head = allocation;
0387     } else {
0388         /* Insert after element */
0389 
0390         allocation->next = element->next;
0391         allocation->previous = element;
0392 
0393         if (element->next) {
0394             (element->next)->previous = allocation;
0395         }
0396 
0397         element->next = allocation;
0398     }
0399 
0400 unlock_and_exit:
0401     status = acpi_ut_release_mutex(ACPI_MTX_MEMORY);
0402     return_ACPI_STATUS(status);
0403 }
0404 
0405 /*******************************************************************************
0406  *
0407  * FUNCTION:    acpi_ut_remove_allocation
0408  *
0409  * PARAMETERS:  allocation          - Address of allocated memory
0410  *              component           - Component type of caller
0411  *              module              - Source file name of caller
0412  *              line                - Line number of caller
0413  *
0414  * RETURN:      Status
0415  *
0416  * DESCRIPTION: Deletes an element from the global allocation tracking list.
0417  *
0418  ******************************************************************************/
0419 
0420 static acpi_status
0421 acpi_ut_remove_allocation(struct acpi_debug_mem_block *allocation,
0422               u32 component, const char *module, u32 line)
0423 {
0424     struct acpi_memory_list *mem_list;
0425     acpi_status status;
0426 
0427     ACPI_FUNCTION_NAME(ut_remove_allocation);
0428 
0429     if (acpi_gbl_disable_mem_tracking) {
0430         return (AE_OK);
0431     }
0432 
0433     mem_list = acpi_gbl_global_list;
0434     if (NULL == mem_list->list_head) {
0435 
0436         /* No allocations! */
0437 
0438         ACPI_ERROR((module, line,
0439                 "Empty allocation list, nothing to free!"));
0440 
0441         return (AE_OK);
0442     }
0443 
0444     status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY);
0445     if (ACPI_FAILURE(status)) {
0446         return (status);
0447     }
0448 
0449     /* Unlink */
0450 
0451     if (allocation->previous) {
0452         (allocation->previous)->next = allocation->next;
0453     } else {
0454         mem_list->list_head = allocation->next;
0455     }
0456 
0457     if (allocation->next) {
0458         (allocation->next)->previous = allocation->previous;
0459     }
0460 
0461     ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Freeing %p, size 0%X\n",
0462               &allocation->user_space, allocation->size));
0463 
0464     /* Mark the segment as deleted */
0465 
0466     memset(&allocation->user_space, 0xEA, allocation->size);
0467 
0468     status = acpi_ut_release_mutex(ACPI_MTX_MEMORY);
0469     return (status);
0470 }
0471 
0472 /*******************************************************************************
0473  *
0474  * FUNCTION:    acpi_ut_dump_allocation_info
0475  *
0476  * PARAMETERS:  None
0477  *
0478  * RETURN:      None
0479  *
0480  * DESCRIPTION: Print some info about the outstanding allocations.
0481  *
0482  ******************************************************************************/
0483 
0484 void acpi_ut_dump_allocation_info(void)
0485 {
0486 /*
0487     struct acpi_memory_list         *mem_list;
0488 */
0489 
0490     ACPI_FUNCTION_TRACE(ut_dump_allocation_info);
0491 
0492 /*
0493     ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
0494         ("%30s: %4d (%3d Kb)\n", "Current allocations",
0495         mem_list->current_count,
0496         ROUND_UP_TO_1K (mem_list->current_size)));
0497 
0498     ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
0499         ("%30s: %4d (%3d Kb)\n", "Max concurrent allocations",
0500         mem_list->max_concurrent_count,
0501         ROUND_UP_TO_1K (mem_list->max_concurrent_size)));
0502 
0503     ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
0504         ("%30s: %4d (%3d Kb)\n", "Total (all) internal objects",
0505         running_object_count,
0506         ROUND_UP_TO_1K (running_object_size)));
0507 
0508     ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
0509         ("%30s: %4d (%3d Kb)\n", "Total (all) allocations",
0510         running_alloc_count,
0511         ROUND_UP_TO_1K (running_alloc_size)));
0512 
0513     ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
0514         ("%30s: %4d (%3d Kb)\n", "Current Nodes",
0515         acpi_gbl_current_node_count,
0516         ROUND_UP_TO_1K (acpi_gbl_current_node_size)));
0517 
0518     ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
0519         ("%30s: %4d (%3d Kb)\n", "Max Nodes",
0520         acpi_gbl_max_concurrent_node_count,
0521         ROUND_UP_TO_1K ((acpi_gbl_max_concurrent_node_count *
0522             sizeof (struct acpi_namespace_node)))));
0523 */
0524     return_VOID;
0525 }
0526 
0527 /*******************************************************************************
0528  *
0529  * FUNCTION:    acpi_ut_dump_allocations
0530  *
0531  * PARAMETERS:  component           - Component(s) to dump info for.
0532  *              module              - Module to dump info for. NULL means all.
0533  *
0534  * RETURN:      None
0535  *
0536  * DESCRIPTION: Print a list of all outstanding allocations.
0537  *
0538  ******************************************************************************/
0539 
0540 void acpi_ut_dump_allocations(u32 component, const char *module)
0541 {
0542     struct acpi_debug_mem_block *element;
0543     union acpi_descriptor *descriptor;
0544     u32 num_outstanding = 0;
0545     u8 descriptor_type;
0546 
0547     ACPI_FUNCTION_TRACE(ut_dump_allocations);
0548 
0549     if (acpi_gbl_disable_mem_tracking) {
0550         return_VOID;
0551     }
0552 
0553     /*
0554      * Walk the allocation list.
0555      */
0556     if (ACPI_FAILURE(acpi_ut_acquire_mutex(ACPI_MTX_MEMORY))) {
0557         return_VOID;
0558     }
0559 
0560     if (!acpi_gbl_global_list) {
0561         goto exit;
0562     }
0563 
0564     element = acpi_gbl_global_list->list_head;
0565     while (element) {
0566         if ((element->component & component) &&
0567             ((module == NULL)
0568              || (0 == strcmp(module, element->module)))) {
0569             descriptor =
0570                 ACPI_CAST_PTR(union acpi_descriptor,
0571                       &element->user_space);
0572 
0573             if (element->size <
0574                 sizeof(struct acpi_common_descriptor)) {
0575                 acpi_os_printf("%p Length 0x%04X %9.9s-%4.4u "
0576                            "[Not a Descriptor - too small]\n",
0577                            descriptor, element->size,
0578                            element->module, element->line);
0579             } else {
0580                 /* Ignore allocated objects that are in a cache */
0581 
0582                 if (ACPI_GET_DESCRIPTOR_TYPE(descriptor) !=
0583                     ACPI_DESC_TYPE_CACHED) {
0584                     acpi_os_printf
0585                         ("%p Length 0x%04X %9.9s-%4.4u [%s] ",
0586                          descriptor, element->size,
0587                          element->module, element->line,
0588                          acpi_ut_get_descriptor_name
0589                          (descriptor));
0590 
0591                     /* Optional object hex dump */
0592 
0593                     if (acpi_gbl_verbose_leak_dump) {
0594                         acpi_os_printf("\n");
0595                         acpi_ut_dump_buffer((u8 *)
0596                                     descriptor,
0597                                     element->
0598                                     size,
0599                                     DB_BYTE_DISPLAY,
0600                                     0);
0601                     }
0602 
0603                     /* Validate the descriptor type using Type field and length */
0604 
0605                     descriptor_type = 0;    /* Not a valid descriptor type */
0606 
0607                     switch (ACPI_GET_DESCRIPTOR_TYPE
0608                         (descriptor)) {
0609                     case ACPI_DESC_TYPE_OPERAND:
0610 
0611                         if (element->size ==
0612                             sizeof(union
0613                                acpi_operand_object))
0614                         {
0615                             descriptor_type =
0616                                 ACPI_DESC_TYPE_OPERAND;
0617                         }
0618                         break;
0619 
0620                     case ACPI_DESC_TYPE_PARSER:
0621 
0622                         if (element->size ==
0623                             sizeof(union
0624                                acpi_parse_object)) {
0625                             descriptor_type =
0626                                 ACPI_DESC_TYPE_PARSER;
0627                         }
0628                         break;
0629 
0630                     case ACPI_DESC_TYPE_NAMED:
0631 
0632                         if (element->size ==
0633                             sizeof(struct
0634                                acpi_namespace_node))
0635                         {
0636                             descriptor_type =
0637                                 ACPI_DESC_TYPE_NAMED;
0638                         }
0639                         break;
0640 
0641                     default:
0642 
0643                         break;
0644                     }
0645 
0646                     /* Display additional info for the major descriptor types */
0647 
0648                     switch (descriptor_type) {
0649                     case ACPI_DESC_TYPE_OPERAND:
0650 
0651                         acpi_os_printf
0652                             ("%12.12s RefCount 0x%04X\n",
0653                              acpi_ut_get_type_name
0654                              (descriptor->object.common.
0655                               type),
0656                              descriptor->object.common.
0657                              reference_count);
0658                         break;
0659 
0660                     case ACPI_DESC_TYPE_PARSER:
0661 
0662                         acpi_os_printf
0663                             ("AmlOpcode 0x%04X\n",
0664                              descriptor->op.asl.
0665                              aml_opcode);
0666                         break;
0667 
0668                     case ACPI_DESC_TYPE_NAMED:
0669 
0670                         acpi_os_printf("%4.4s\n",
0671                                    acpi_ut_get_node_name
0672                                    (&descriptor->
0673                                 node));
0674                         break;
0675 
0676                     default:
0677 
0678                         acpi_os_printf("\n");
0679                         break;
0680                     }
0681                 }
0682             }
0683 
0684             num_outstanding++;
0685         }
0686 
0687         element = element->next;
0688     }
0689 
0690 exit:
0691     (void)acpi_ut_release_mutex(ACPI_MTX_MEMORY);
0692 
0693     /* Print summary */
0694 
0695     if (!num_outstanding) {
0696         ACPI_INFO(("No outstanding allocations"));
0697     } else {
0698         ACPI_ERROR((AE_INFO, "%u (0x%X) Outstanding cache allocations",
0699                 num_outstanding, num_outstanding));
0700     }
0701 
0702     return_VOID;
0703 }
0704 
0705 #endif              /* ACPI_DBG_TRACK_ALLOCATIONS */