linux/drivers/acpi/acpica/uttrack.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Module Name: uttrack - Memory allocation tracking routines (debug only)
   5 *
   6 * Copyright (C) 2000 - 2021, Intel Corp.
   7 *
   8 *****************************************************************************/
   9
  10/*
  11 * These procedures are used for tracking memory leaks in the subsystem, and
  12 * they get compiled out when the ACPI_DBG_TRACK_ALLOCATIONS is not set.
  13 *
  14 * Each memory allocation is tracked via a doubly linked list. Each
  15 * element contains the caller's component, module name, function name, and
  16 * line number. acpi_ut_allocate and acpi_ut_allocate_zeroed call
  17 * acpi_ut_track_allocation to add an element to the list; deletion
  18 * occurs in the body of acpi_ut_free.
  19 */
  20
  21#include <acpi/acpi.h>
  22#include "accommon.h"
  23
  24#ifdef ACPI_DBG_TRACK_ALLOCATIONS
  25
  26#define _COMPONENT          ACPI_UTILITIES
  27ACPI_MODULE_NAME("uttrack")
  28
  29/* Local prototypes */
  30static struct acpi_debug_mem_block *acpi_ut_find_allocation(struct
  31                                                            acpi_debug_mem_block
  32                                                            *allocation);
  33
  34static acpi_status
  35acpi_ut_track_allocation(struct acpi_debug_mem_block *address,
  36                         acpi_size size,
  37                         u8 alloc_type,
  38                         u32 component, const char *module, u32 line);
  39
  40static acpi_status
  41acpi_ut_remove_allocation(struct acpi_debug_mem_block *address,
  42                          u32 component, const char *module, u32 line);
  43
  44/*******************************************************************************
  45 *
  46 * FUNCTION:    acpi_ut_create_list
  47 *
  48 * PARAMETERS:  cache_name      - Ascii name for the cache
  49 *              object_size     - Size of each cached object
  50 *              return_cache    - Where the new cache object is returned
  51 *
  52 * RETURN:      Status
  53 *
  54 * DESCRIPTION: Create a local memory list for tracking purposed
  55 *
  56 ******************************************************************************/
  57
  58acpi_status
  59acpi_ut_create_list(const char *list_name,
  60                    u16 object_size, struct acpi_memory_list **return_cache)
  61{
  62        struct acpi_memory_list *cache;
  63
  64        cache = acpi_os_allocate_zeroed(sizeof(struct acpi_memory_list));
  65        if (!cache) {
  66                return (AE_NO_MEMORY);
  67        }
  68
  69        cache->list_name = list_name;
  70        cache->object_size = object_size;
  71
  72        *return_cache = cache;
  73        return (AE_OK);
  74}
  75
  76/*******************************************************************************
  77 *
  78 * FUNCTION:    acpi_ut_allocate_and_track
  79 *
  80 * PARAMETERS:  size                - Size of the allocation
  81 *              component           - Component type of caller
  82 *              module              - Source file name of caller
  83 *              line                - Line number of caller
  84 *
  85 * RETURN:      Address of the allocated memory on success, NULL on failure.
  86 *
  87 * DESCRIPTION: The subsystem's equivalent of malloc.
  88 *
  89 ******************************************************************************/
  90
  91void *acpi_ut_allocate_and_track(acpi_size size,
  92                                 u32 component, const char *module, u32 line)
  93{
  94        struct acpi_debug_mem_block *allocation;
  95        acpi_status status;
  96
  97        /* Check for an inadvertent size of zero bytes */
  98
  99        if (!size) {
 100                ACPI_WARNING((module, line,
 101                              "Attempt to allocate zero bytes, allocating 1 byte"));
 102                size = 1;
 103        }
 104
 105        allocation =
 106            acpi_os_allocate(size + sizeof(struct acpi_debug_mem_header));
 107        if (!allocation) {
 108
 109                /* Report allocation error */
 110
 111                ACPI_WARNING((module, line,
 112                              "Could not allocate size %u", (u32)size));
 113
 114                return (NULL);
 115        }
 116
 117        status =
 118            acpi_ut_track_allocation(allocation, size, ACPI_MEM_MALLOC,
 119                                     component, module, line);
 120        if (ACPI_FAILURE(status)) {
 121                acpi_os_free(allocation);
 122                return (NULL);
 123        }
 124
 125        acpi_gbl_global_list->total_allocated++;
 126        acpi_gbl_global_list->total_size += (u32)size;
 127        acpi_gbl_global_list->current_total_size += (u32)size;
 128
 129        if (acpi_gbl_global_list->current_total_size >
 130            acpi_gbl_global_list->max_occupied) {
 131                acpi_gbl_global_list->max_occupied =
 132                    acpi_gbl_global_list->current_total_size;
 133        }
 134
 135        return ((void *)&allocation->user_space);
 136}
 137
 138/*******************************************************************************
 139 *
 140 * FUNCTION:    acpi_ut_allocate_zeroed_and_track
 141 *
 142 * PARAMETERS:  size                - Size of the allocation
 143 *              component           - Component type of caller
 144 *              module              - Source file name of caller
 145 *              line                - Line number of caller
 146 *
 147 * RETURN:      Address of the allocated memory on success, NULL on failure.
 148 *
 149 * DESCRIPTION: Subsystem equivalent of calloc.
 150 *
 151 ******************************************************************************/
 152
 153void *acpi_ut_allocate_zeroed_and_track(acpi_size size,
 154                                        u32 component,
 155                                        const char *module, u32 line)
 156{
 157        struct acpi_debug_mem_block *allocation;
 158        acpi_status status;
 159
 160        /* Check for an inadvertent size of zero bytes */
 161
 162        if (!size) {
 163                ACPI_WARNING((module, line,
 164                              "Attempt to allocate zero bytes, allocating 1 byte"));
 165                size = 1;
 166        }
 167
 168        allocation =
 169            acpi_os_allocate_zeroed(size +
 170                                    sizeof(struct acpi_debug_mem_header));
 171        if (!allocation) {
 172
 173                /* Report allocation error */
 174
 175                ACPI_ERROR((module, line,
 176                            "Could not allocate size %u", (u32)size));
 177                return (NULL);
 178        }
 179
 180        status = acpi_ut_track_allocation(allocation, size,
 181                                          ACPI_MEM_CALLOC, component, module,
 182                                          line);
 183        if (ACPI_FAILURE(status)) {
 184                acpi_os_free(allocation);
 185                return (NULL);
 186        }
 187
 188        acpi_gbl_global_list->total_allocated++;
 189        acpi_gbl_global_list->total_size += (u32)size;
 190        acpi_gbl_global_list->current_total_size += (u32)size;
 191
 192        if (acpi_gbl_global_list->current_total_size >
 193            acpi_gbl_global_list->max_occupied) {
 194                acpi_gbl_global_list->max_occupied =
 195                    acpi_gbl_global_list->current_total_size;
 196        }
 197
 198        return ((void *)&allocation->user_space);
 199}
 200
 201/*******************************************************************************
 202 *
 203 * FUNCTION:    acpi_ut_free_and_track
 204 *
 205 * PARAMETERS:  allocation          - Address of the memory to deallocate
 206 *              component           - Component type of caller
 207 *              module              - Source file name of caller
 208 *              line                - Line number of caller
 209 *
 210 * RETURN:      None
 211 *
 212 * DESCRIPTION: Frees the memory at Allocation
 213 *
 214 ******************************************************************************/
 215
 216void
 217acpi_ut_free_and_track(void *allocation,
 218                       u32 component, const char *module, u32 line)
 219{
 220        struct acpi_debug_mem_block *debug_block;
 221        acpi_status status;
 222
 223        ACPI_FUNCTION_TRACE_PTR(ut_free, allocation);
 224
 225        if (NULL == allocation) {
 226                ACPI_ERROR((module, line, "Attempt to delete a NULL address"));
 227
 228                return_VOID;
 229        }
 230
 231        debug_block = ACPI_CAST_PTR(struct acpi_debug_mem_block,
 232                                    (((char *)allocation) -
 233                                     sizeof(struct acpi_debug_mem_header)));
 234
 235        acpi_gbl_global_list->total_freed++;
 236        acpi_gbl_global_list->current_total_size -= debug_block->size;
 237
 238        status =
 239            acpi_ut_remove_allocation(debug_block, component, module, line);
 240        if (ACPI_FAILURE(status)) {
 241                ACPI_EXCEPTION((AE_INFO, status, "Could not free memory"));
 242        }
 243
 244        acpi_os_free(debug_block);
 245        ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "%p freed (block %p)\n",
 246                          allocation, debug_block));
 247        return_VOID;
 248}
 249
 250/*******************************************************************************
 251 *
 252 * FUNCTION:    acpi_ut_find_allocation
 253 *
 254 * PARAMETERS:  allocation              - Address of allocated memory
 255 *
 256 * RETURN:      Three cases:
 257 *              1) List is empty, NULL is returned.
 258 *              2) Element was found. Returns Allocation parameter.
 259 *              3) Element was not found. Returns position where it should be
 260 *                  inserted into the list.
 261 *
 262 * DESCRIPTION: Searches for an element in the global allocation tracking list.
 263 *              If the element is not found, returns the location within the
 264 *              list where the element should be inserted.
 265 *
 266 *              Note: The list is ordered by larger-to-smaller addresses.
 267 *
 268 *              This global list is used to detect memory leaks in ACPICA as
 269 *              well as other issues such as an attempt to release the same
 270 *              internal object more than once. Although expensive as far
 271 *              as cpu time, this list is much more helpful for finding these
 272 *              types of issues than using memory leak detectors outside of
 273 *              the ACPICA code.
 274 *
 275 ******************************************************************************/
 276
 277static struct acpi_debug_mem_block *acpi_ut_find_allocation(struct
 278                                                            acpi_debug_mem_block
 279                                                            *allocation)
 280{
 281        struct acpi_debug_mem_block *element;
 282
 283        element = acpi_gbl_global_list->list_head;
 284        if (!element) {
 285                return (NULL);
 286        }
 287
 288        /*
 289         * Search for the address.
 290         *
 291         * Note: List is ordered by larger-to-smaller addresses, on the
 292         * assumption that a new allocation usually has a larger address
 293         * than previous allocations.
 294         */
 295        while (element > allocation) {
 296
 297                /* Check for end-of-list */
 298
 299                if (!element->next) {
 300                        return (element);
 301                }
 302
 303                element = element->next;
 304        }
 305
 306        if (element == allocation) {
 307                return (element);
 308        }
 309
 310        return (element->previous);
 311}
 312
 313/*******************************************************************************
 314 *
 315 * FUNCTION:    acpi_ut_track_allocation
 316 *
 317 * PARAMETERS:  allocation          - Address of allocated memory
 318 *              size                - Size of the allocation
 319 *              alloc_type          - MEM_MALLOC or MEM_CALLOC
 320 *              component           - Component type of caller
 321 *              module              - Source file name of caller
 322 *              line                - Line number of caller
 323 *
 324 * RETURN:      Status
 325 *
 326 * DESCRIPTION: Inserts an element into the global allocation tracking list.
 327 *
 328 ******************************************************************************/
 329
 330static acpi_status
 331acpi_ut_track_allocation(struct acpi_debug_mem_block *allocation,
 332                         acpi_size size,
 333                         u8 alloc_type,
 334                         u32 component, const char *module, u32 line)
 335{
 336        struct acpi_memory_list *mem_list;
 337        struct acpi_debug_mem_block *element;
 338        acpi_status status = AE_OK;
 339
 340        ACPI_FUNCTION_TRACE_PTR(ut_track_allocation, allocation);
 341
 342        if (acpi_gbl_disable_mem_tracking) {
 343                return_ACPI_STATUS(AE_OK);
 344        }
 345
 346        mem_list = acpi_gbl_global_list;
 347        status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY);
 348        if (ACPI_FAILURE(status)) {
 349                return_ACPI_STATUS(status);
 350        }
 351
 352        /*
 353         * Search the global list for this address to make sure it is not
 354         * already present. This will catch several kinds of problems.
 355         */
 356        element = acpi_ut_find_allocation(allocation);
 357        if (element == allocation) {
 358                ACPI_ERROR((AE_INFO,
 359                            "UtTrackAllocation: Allocation (%p) already present in global list!",
 360                            allocation));
 361                goto unlock_and_exit;
 362        }
 363
 364        /* Fill in the instance data */
 365
 366        allocation->size = (u32)size;
 367        allocation->alloc_type = alloc_type;
 368        allocation->component = component;
 369        allocation->line = line;
 370
 371        acpi_ut_safe_strncpy(allocation->module, (char *)module,
 372                             ACPI_MAX_MODULE_NAME);
 373
 374        if (!element) {
 375
 376                /* Insert at list head */
 377
 378                if (mem_list->list_head) {
 379                        ((struct acpi_debug_mem_block *)(mem_list->list_head))->
 380                            previous = allocation;
 381                }
 382
 383                allocation->next = mem_list->list_head;
 384                allocation->previous = NULL;
 385
 386                mem_list->list_head = allocation;
 387        } else {
 388                /* Insert after element */
 389
 390                allocation->next = element->next;
 391                allocation->previous = element;
 392
 393                if (element->next) {
 394                        (element->next)->previous = allocation;
 395                }
 396
 397                element->next = allocation;
 398        }
 399
 400unlock_and_exit:
 401        status = acpi_ut_release_mutex(ACPI_MTX_MEMORY);
 402        return_ACPI_STATUS(status);
 403}
 404
 405/*******************************************************************************
 406 *
 407 * FUNCTION:    acpi_ut_remove_allocation
 408 *
 409 * PARAMETERS:  allocation          - Address of allocated memory
 410 *              component           - Component type of caller
 411 *              module              - Source file name of caller
 412 *              line                - Line number of caller
 413 *
 414 * RETURN:      Status
 415 *
 416 * DESCRIPTION: Deletes an element from the global allocation tracking list.
 417 *
 418 ******************************************************************************/
 419
 420static acpi_status
 421acpi_ut_remove_allocation(struct acpi_debug_mem_block *allocation,
 422                          u32 component, const char *module, u32 line)
 423{
 424        struct acpi_memory_list *mem_list;
 425        acpi_status status;
 426
 427        ACPI_FUNCTION_NAME(ut_remove_allocation);
 428
 429        if (acpi_gbl_disable_mem_tracking) {
 430                return (AE_OK);
 431        }
 432
 433        mem_list = acpi_gbl_global_list;
 434        if (NULL == mem_list->list_head) {
 435
 436                /* No allocations! */
 437
 438                ACPI_ERROR((module, line,
 439                            "Empty allocation list, nothing to free!"));
 440
 441                return (AE_OK);
 442        }
 443
 444        status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY);
 445        if (ACPI_FAILURE(status)) {
 446                return (status);
 447        }
 448
 449        /* Unlink */
 450
 451        if (allocation->previous) {
 452                (allocation->previous)->next = allocation->next;
 453        } else {
 454                mem_list->list_head = allocation->next;
 455        }
 456
 457        if (allocation->next) {
 458                (allocation->next)->previous = allocation->previous;
 459        }
 460
 461        ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Freeing %p, size 0%X\n",
 462                          &allocation->user_space, allocation->size));
 463
 464        /* Mark the segment as deleted */
 465
 466        memset(&allocation->user_space, 0xEA, allocation->size);
 467
 468        status = acpi_ut_release_mutex(ACPI_MTX_MEMORY);
 469        return (status);
 470}
 471
 472/*******************************************************************************
 473 *
 474 * FUNCTION:    acpi_ut_dump_allocation_info
 475 *
 476 * PARAMETERS:  None
 477 *
 478 * RETURN:      None
 479 *
 480 * DESCRIPTION: Print some info about the outstanding allocations.
 481 *
 482 ******************************************************************************/
 483
 484void acpi_ut_dump_allocation_info(void)
 485{
 486/*
 487        struct acpi_memory_list         *mem_list;
 488*/
 489
 490        ACPI_FUNCTION_TRACE(ut_dump_allocation_info);
 491
 492/*
 493        ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
 494                ("%30s: %4d (%3d Kb)\n", "Current allocations",
 495                mem_list->current_count,
 496                ROUND_UP_TO_1K (mem_list->current_size)));
 497
 498        ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
 499                ("%30s: %4d (%3d Kb)\n", "Max concurrent allocations",
 500                mem_list->max_concurrent_count,
 501                ROUND_UP_TO_1K (mem_list->max_concurrent_size)));
 502
 503        ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
 504                ("%30s: %4d (%3d Kb)\n", "Total (all) internal objects",
 505                running_object_count,
 506                ROUND_UP_TO_1K (running_object_size)));
 507
 508        ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
 509                ("%30s: %4d (%3d Kb)\n", "Total (all) allocations",
 510                running_alloc_count,
 511                ROUND_UP_TO_1K (running_alloc_size)));
 512
 513        ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
 514                ("%30s: %4d (%3d Kb)\n", "Current Nodes",
 515                acpi_gbl_current_node_count,
 516                ROUND_UP_TO_1K (acpi_gbl_current_node_size)));
 517
 518        ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
 519                ("%30s: %4d (%3d Kb)\n", "Max Nodes",
 520                acpi_gbl_max_concurrent_node_count,
 521                ROUND_UP_TO_1K ((acpi_gbl_max_concurrent_node_count *
 522                        sizeof (struct acpi_namespace_node)))));
 523*/
 524        return_VOID;
 525}
 526
 527/*******************************************************************************
 528 *
 529 * FUNCTION:    acpi_ut_dump_allocations
 530 *
 531 * PARAMETERS:  component           - Component(s) to dump info for.
 532 *              module              - Module to dump info for. NULL means all.
 533 *
 534 * RETURN:      None
 535 *
 536 * DESCRIPTION: Print a list of all outstanding allocations.
 537 *
 538 ******************************************************************************/
 539
 540void acpi_ut_dump_allocations(u32 component, const char *module)
 541{
 542        struct acpi_debug_mem_block *element;
 543        union acpi_descriptor *descriptor;
 544        u32 num_outstanding = 0;
 545        u8 descriptor_type;
 546
 547        ACPI_FUNCTION_TRACE(ut_dump_allocations);
 548
 549        if (acpi_gbl_disable_mem_tracking) {
 550                return_VOID;
 551        }
 552
 553        /*
 554         * Walk the allocation list.
 555         */
 556        if (ACPI_FAILURE(acpi_ut_acquire_mutex(ACPI_MTX_MEMORY))) {
 557                return_VOID;
 558        }
 559
 560        if (!acpi_gbl_global_list) {
 561                goto exit;
 562        }
 563
 564        element = acpi_gbl_global_list->list_head;
 565        while (element) {
 566                if ((element->component & component) &&
 567                    ((module == NULL)
 568                     || (0 == strcmp(module, element->module)))) {
 569                        descriptor =
 570                            ACPI_CAST_PTR(union acpi_descriptor,
 571                                          &element->user_space);
 572
 573                        if (element->size <
 574                            sizeof(struct acpi_common_descriptor)) {
 575                                acpi_os_printf("%p Length 0x%04X %9.9s-%4.4u "
 576                                               "[Not a Descriptor - too small]\n",
 577                                               descriptor, element->size,
 578                                               element->module, element->line);
 579                        } else {
 580                                /* Ignore allocated objects that are in a cache */
 581
 582                                if (ACPI_GET_DESCRIPTOR_TYPE(descriptor) !=
 583                                    ACPI_DESC_TYPE_CACHED) {
 584                                        acpi_os_printf
 585                                            ("%p Length 0x%04X %9.9s-%4.4u [%s] ",
 586                                             descriptor, element->size,
 587                                             element->module, element->line,
 588                                             acpi_ut_get_descriptor_name
 589                                             (descriptor));
 590
 591                                        /* Optional object hex dump */
 592
 593                                        if (acpi_gbl_verbose_leak_dump) {
 594                                                acpi_os_printf("\n");
 595                                                acpi_ut_dump_buffer((u8 *)
 596                                                                    descriptor,
 597                                                                    element->
 598                                                                    size,
 599                                                                    DB_BYTE_DISPLAY,
 600                                                                    0);
 601                                        }
 602
 603                                        /* Validate the descriptor type using Type field and length */
 604
 605                                        descriptor_type = 0;    /* Not a valid descriptor type */
 606
 607                                        switch (ACPI_GET_DESCRIPTOR_TYPE
 608                                                (descriptor)) {
 609                                        case ACPI_DESC_TYPE_OPERAND:
 610
 611                                                if (element->size ==
 612                                                    sizeof(union
 613                                                           acpi_operand_object))
 614                                                {
 615                                                        descriptor_type =
 616                                                            ACPI_DESC_TYPE_OPERAND;
 617                                                }
 618                                                break;
 619
 620                                        case ACPI_DESC_TYPE_PARSER:
 621
 622                                                if (element->size ==
 623                                                    sizeof(union
 624                                                           acpi_parse_object)) {
 625                                                        descriptor_type =
 626                                                            ACPI_DESC_TYPE_PARSER;
 627                                                }
 628                                                break;
 629
 630                                        case ACPI_DESC_TYPE_NAMED:
 631
 632                                                if (element->size ==
 633                                                    sizeof(struct
 634                                                           acpi_namespace_node))
 635                                                {
 636                                                        descriptor_type =
 637                                                            ACPI_DESC_TYPE_NAMED;
 638                                                }
 639                                                break;
 640
 641                                        default:
 642
 643                                                break;
 644                                        }
 645
 646                                        /* Display additional info for the major descriptor types */
 647
 648                                        switch (descriptor_type) {
 649                                        case ACPI_DESC_TYPE_OPERAND:
 650
 651                                                acpi_os_printf
 652                                                    ("%12.12s RefCount 0x%04X\n",
 653                                                     acpi_ut_get_type_name
 654                                                     (descriptor->object.common.
 655                                                      type),
 656                                                     descriptor->object.common.
 657                                                     reference_count);
 658                                                break;
 659
 660                                        case ACPI_DESC_TYPE_PARSER:
 661
 662                                                acpi_os_printf
 663                                                    ("AmlOpcode 0x%04X\n",
 664                                                     descriptor->op.asl.
 665                                                     aml_opcode);
 666                                                break;
 667
 668                                        case ACPI_DESC_TYPE_NAMED:
 669
 670                                                acpi_os_printf("%4.4s\n",
 671                                                               acpi_ut_get_node_name
 672                                                               (&descriptor->
 673                                                                node));
 674                                                break;
 675
 676                                        default:
 677
 678                                                acpi_os_printf("\n");
 679                                                break;
 680                                        }
 681                                }
 682                        }
 683
 684                        num_outstanding++;
 685                }
 686
 687                element = element->next;
 688        }
 689
 690exit:
 691        (void)acpi_ut_release_mutex(ACPI_MTX_MEMORY);
 692
 693        /* Print summary */
 694
 695        if (!num_outstanding) {
 696                ACPI_INFO(("No outstanding allocations"));
 697        } else {
 698                ACPI_ERROR((AE_INFO, "%u (0x%X) Outstanding cache allocations",
 699                            num_outstanding, num_outstanding));
 700        }
 701
 702        return_VOID;
 703}
 704
 705#endif                          /* ACPI_DBG_TRACK_ALLOCATIONS */
 706
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.