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