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 - 2023, 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 27 ACPI_MODULE_NAME("uttrack") 28 29 /* Local prototypes */ 30 static struct acpi_debug_mem_block *acpi_ut_find_allocation(struct 31 acpi_debug_mem_block 32 *allocation); 33 34 static acpi_status 35 acpi_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 40 static acpi_status 41 acpi_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 58 acpi_status 59 acpi_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 91 void *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 153 void *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 216 void 217 acpi_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 277 static 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 330 static acpi_status 331 acpi_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 400 unlock_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 420 static acpi_status 421 acpi_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 484 void 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 540 void 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 690 exit: 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