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