1 /****************************************************************************** 2 * 3 * Module Name: uttrack - Memory allocation tracking routines (debug only) 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2011, 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. AcpiUtAllocate and AcpiUtAllocateZeroed call 51 * AcpiUtTrackAllocation to add an element to the list; deletion 52 * occurs in the body of AcpiUtFree. 53 */ 54 55 #define __UTTRACK_C__ 56 57 #include "acpi.h" 58 #include "accommon.h" 59 60 #ifdef ACPI_DBG_TRACK_ALLOCATIONS 61 62 #define _COMPONENT ACPI_UTILITIES 63 ACPI_MODULE_NAME ("uttrack") 64 65 /* Local prototypes */ 66 67 static ACPI_DEBUG_MEM_BLOCK * 68 AcpiUtFindAllocation ( 69 void *Allocation); 70 71 static ACPI_STATUS 72 AcpiUtTrackAllocation ( 73 ACPI_DEBUG_MEM_BLOCK *Address, 74 ACPI_SIZE Size, 75 UINT8 AllocType, 76 UINT32 Component, 77 const char *Module, 78 UINT32 Line); 79 80 static ACPI_STATUS 81 AcpiUtRemoveAllocation ( 82 ACPI_DEBUG_MEM_BLOCK *Address, 83 UINT32 Component, 84 const char *Module, 85 UINT32 Line); 86 87 88 /******************************************************************************* 89 * 90 * FUNCTION: AcpiUtCreateList 91 * 92 * PARAMETERS: CacheName - Ascii name for the cache 93 * ObjectSize - Size of each cached object 94 * ReturnCache - Where the new cache object is returned 95 * 96 * RETURN: Status 97 * 98 * DESCRIPTION: Create a local memory list for tracking purposed 99 * 100 ******************************************************************************/ 101 102 ACPI_STATUS 103 AcpiUtCreateList ( 104 char *ListName, 105 UINT16 ObjectSize, 106 ACPI_MEMORY_LIST **ReturnCache) 107 { 108 ACPI_MEMORY_LIST *Cache; 109 110 111 Cache = AcpiOsAllocate (sizeof (ACPI_MEMORY_LIST)); 112 if (!Cache) 113 { 114 return (AE_NO_MEMORY); 115 } 116 117 ACPI_MEMSET (Cache, 0, sizeof (ACPI_MEMORY_LIST)); 118 119 Cache->ListName = ListName; 120 Cache->ObjectSize = ObjectSize; 121 122 *ReturnCache = Cache; 123 return (AE_OK); 124 } 125 126 127 /******************************************************************************* 128 * 129 * FUNCTION: AcpiUtAllocateAndTrack 130 * 131 * PARAMETERS: Size - Size of the allocation 132 * Component - Component type of caller 133 * Module - Source file name of caller 134 * Line - Line number of caller 135 * 136 * RETURN: Address of the allocated memory on success, NULL on failure. 137 * 138 * DESCRIPTION: The subsystem's equivalent of malloc. 139 * 140 ******************************************************************************/ 141 142 void * 143 AcpiUtAllocateAndTrack ( 144 ACPI_SIZE Size, 145 UINT32 Component, 146 const char *Module, 147 UINT32 Line) 148 { 149 ACPI_DEBUG_MEM_BLOCK *Allocation; 150 ACPI_STATUS Status; 151 152 153 Allocation = AcpiUtAllocate (Size + sizeof (ACPI_DEBUG_MEM_HEADER), 154 Component, Module, Line); 155 if (!Allocation) 156 { 157 return (NULL); 158 } 159 160 Status = AcpiUtTrackAllocation (Allocation, Size, 161 ACPI_MEM_MALLOC, Component, Module, Line); 162 if (ACPI_FAILURE (Status)) 163 { 164 AcpiOsFree (Allocation); 165 return (NULL); 166 } 167 168 AcpiGbl_GlobalList->TotalAllocated++; 169 AcpiGbl_GlobalList->TotalSize += (UINT32) Size; 170 AcpiGbl_GlobalList->CurrentTotalSize += (UINT32) Size; 171 if (AcpiGbl_GlobalList->CurrentTotalSize > AcpiGbl_GlobalList->MaxOccupied) 172 { 173 AcpiGbl_GlobalList->MaxOccupied = AcpiGbl_GlobalList->CurrentTotalSize; 174 } 175 176 return ((void *) &Allocation->UserSpace); 177 } 178 179 180 /******************************************************************************* 181 * 182 * FUNCTION: AcpiUtAllocateZeroedAndTrack 183 * 184 * PARAMETERS: Size - Size of the allocation 185 * Component - Component type of caller 186 * Module - Source file name of caller 187 * Line - Line number of caller 188 * 189 * RETURN: Address of the allocated memory on success, NULL on failure. 190 * 191 * DESCRIPTION: Subsystem equivalent of calloc. 192 * 193 ******************************************************************************/ 194 195 void * 196 AcpiUtAllocateZeroedAndTrack ( 197 ACPI_SIZE Size, 198 UINT32 Component, 199 const char *Module, 200 UINT32 Line) 201 { 202 ACPI_DEBUG_MEM_BLOCK *Allocation; 203 ACPI_STATUS Status; 204 205 206 Allocation = AcpiUtAllocateZeroed (Size + sizeof (ACPI_DEBUG_MEM_HEADER), 207 Component, Module, Line); 208 if (!Allocation) 209 { 210 /* Report allocation error */ 211 212 ACPI_ERROR ((Module, Line, 213 "Could not allocate size %u", (UINT32) Size)); 214 return (NULL); 215 } 216 217 Status = AcpiUtTrackAllocation (Allocation, Size, 218 ACPI_MEM_CALLOC, Component, Module, Line); 219 if (ACPI_FAILURE (Status)) 220 { 221 AcpiOsFree (Allocation); 222 return (NULL); 223 } 224 225 AcpiGbl_GlobalList->TotalAllocated++; 226 AcpiGbl_GlobalList->TotalSize += (UINT32) Size; 227 AcpiGbl_GlobalList->CurrentTotalSize += (UINT32) Size; 228 if (AcpiGbl_GlobalList->CurrentTotalSize > AcpiGbl_GlobalList->MaxOccupied) 229 { 230 AcpiGbl_GlobalList->MaxOccupied = AcpiGbl_GlobalList->CurrentTotalSize; 231 } 232 233 return ((void *) &Allocation->UserSpace); 234 } 235 236 237 /******************************************************************************* 238 * 239 * FUNCTION: AcpiUtFreeAndTrack 240 * 241 * PARAMETERS: Allocation - Address of the memory to deallocate 242 * Component - Component type of caller 243 * Module - Source file name of caller 244 * Line - Line number of caller 245 * 246 * RETURN: None 247 * 248 * DESCRIPTION: Frees the memory at Allocation 249 * 250 ******************************************************************************/ 251 252 void 253 AcpiUtFreeAndTrack ( 254 void *Allocation, 255 UINT32 Component, 256 const char *Module, 257 UINT32 Line) 258 { 259 ACPI_DEBUG_MEM_BLOCK *DebugBlock; 260 ACPI_STATUS Status; 261 262 263 ACPI_FUNCTION_TRACE_PTR (UtFree, Allocation); 264 265 266 if (NULL == Allocation) 267 { 268 ACPI_ERROR ((Module, Line, 269 "Attempt to delete a NULL address")); 270 271 return_VOID; 272 } 273 274 DebugBlock = ACPI_CAST_PTR (ACPI_DEBUG_MEM_BLOCK, 275 (((char *) Allocation) - sizeof (ACPI_DEBUG_MEM_HEADER))); 276 277 AcpiGbl_GlobalList->TotalFreed++; 278 AcpiGbl_GlobalList->CurrentTotalSize -= DebugBlock->Size; 279 280 Status = AcpiUtRemoveAllocation (DebugBlock, 281 Component, Module, Line); 282 if (ACPI_FAILURE (Status)) 283 { 284 ACPI_EXCEPTION ((AE_INFO, Status, "Could not free memory")); 285 } 286 287 AcpiOsFree (DebugBlock); 288 ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "%p freed\n", Allocation)); 289 return_VOID; 290 } 291 292 293 /******************************************************************************* 294 * 295 * FUNCTION: AcpiUtFindAllocation 296 * 297 * PARAMETERS: Allocation - Address of allocated memory 298 * 299 * RETURN: A list element if found; NULL otherwise. 300 * 301 * DESCRIPTION: Searches for an element in the global allocation tracking list. 302 * 303 ******************************************************************************/ 304 305 static ACPI_DEBUG_MEM_BLOCK * 306 AcpiUtFindAllocation ( 307 void *Allocation) 308 { 309 ACPI_DEBUG_MEM_BLOCK *Element; 310 311 312 ACPI_FUNCTION_ENTRY (); 313 314 315 Element = AcpiGbl_GlobalList->ListHead; 316 317 /* Search for the address. */ 318 319 while (Element) 320 { 321 if (Element == Allocation) 322 { 323 return (Element); 324 } 325 326 Element = Element->Next; 327 } 328 329 return (NULL); 330 } 331 332 333 /******************************************************************************* 334 * 335 * FUNCTION: AcpiUtTrackAllocation 336 * 337 * PARAMETERS: Allocation - Address of allocated memory 338 * Size - Size of the allocation 339 * AllocType - MEM_MALLOC or MEM_CALLOC 340 * Component - Component type of caller 341 * Module - Source file name of caller 342 * Line - Line number of caller 343 * 344 * RETURN: None. 345 * 346 * DESCRIPTION: Inserts an element into the global allocation tracking list. 347 * 348 ******************************************************************************/ 349 350 static ACPI_STATUS 351 AcpiUtTrackAllocation ( 352 ACPI_DEBUG_MEM_BLOCK *Allocation, 353 ACPI_SIZE Size, 354 UINT8 AllocType, 355 UINT32 Component, 356 const char *Module, 357 UINT32 Line) 358 { 359 ACPI_MEMORY_LIST *MemList; 360 ACPI_DEBUG_MEM_BLOCK *Element; 361 ACPI_STATUS Status = AE_OK; 362 363 364 ACPI_FUNCTION_TRACE_PTR (UtTrackAllocation, Allocation); 365 366 367 if (AcpiGbl_DisableMemTracking) 368 { 369 return_ACPI_STATUS (AE_OK); 370 } 371 372 MemList = AcpiGbl_GlobalList; 373 Status = AcpiUtAcquireMutex (ACPI_MTX_MEMORY); 374 if (ACPI_FAILURE (Status)) 375 { 376 return_ACPI_STATUS (Status); 377 } 378 379 /* 380 * Search list for this address to make sure it is not already on the list. 381 * This will catch several kinds of problems. 382 */ 383 Element = AcpiUtFindAllocation (Allocation); 384 if (Element) 385 { 386 ACPI_ERROR ((AE_INFO, 387 "UtTrackAllocation: Allocation already present in list! (%p)", 388 Allocation)); 389 390 ACPI_ERROR ((AE_INFO, "Element %p Address %p", 391 Element, Allocation)); 392 393 goto UnlockAndExit; 394 } 395 396 /* Fill in the instance data. */ 397 398 Allocation->Size = (UINT32) Size; 399 Allocation->AllocType = AllocType; 400 Allocation->Component = Component; 401 Allocation->Line = Line; 402 403 ACPI_STRNCPY (Allocation->Module, Module, ACPI_MAX_MODULE_NAME); 404 Allocation->Module[ACPI_MAX_MODULE_NAME-1] = 0; 405 406 /* Insert at list head */ 407 408 if (MemList->ListHead) 409 { 410 ((ACPI_DEBUG_MEM_BLOCK *)(MemList->ListHead))->Previous = Allocation; 411 } 412 413 Allocation->Next = MemList->ListHead; 414 Allocation->Previous = NULL; 415 416 MemList->ListHead = Allocation; 417 418 419 UnlockAndExit: 420 Status = AcpiUtReleaseMutex (ACPI_MTX_MEMORY); 421 return_ACPI_STATUS (Status); 422 } 423 424 425 /******************************************************************************* 426 * 427 * FUNCTION: AcpiUtRemoveAllocation 428 * 429 * PARAMETERS: Allocation - Address of allocated memory 430 * Component - Component type of caller 431 * Module - Source file name of caller 432 * Line - Line number of caller 433 * 434 * RETURN: 435 * 436 * DESCRIPTION: Deletes an element from the global allocation tracking list. 437 * 438 ******************************************************************************/ 439 440 static ACPI_STATUS 441 AcpiUtRemoveAllocation ( 442 ACPI_DEBUG_MEM_BLOCK *Allocation, 443 UINT32 Component, 444 const char *Module, 445 UINT32 Line) 446 { 447 ACPI_MEMORY_LIST *MemList; 448 ACPI_STATUS Status; 449 450 451 ACPI_FUNCTION_TRACE (UtRemoveAllocation); 452 453 454 if (AcpiGbl_DisableMemTracking) 455 { 456 return_ACPI_STATUS (AE_OK); 457 } 458 459 MemList = AcpiGbl_GlobalList; 460 if (NULL == MemList->ListHead) 461 { 462 /* No allocations! */ 463 464 ACPI_ERROR ((Module, Line, 465 "Empty allocation list, nothing to free!")); 466 467 return_ACPI_STATUS (AE_OK); 468 } 469 470 Status = AcpiUtAcquireMutex (ACPI_MTX_MEMORY); 471 if (ACPI_FAILURE (Status)) 472 { 473 return_ACPI_STATUS (Status); 474 } 475 476 /* Unlink */ 477 478 if (Allocation->Previous) 479 { 480 (Allocation->Previous)->Next = Allocation->Next; 481 } 482 else 483 { 484 MemList->ListHead = Allocation->Next; 485 } 486 487 if (Allocation->Next) 488 { 489 (Allocation->Next)->Previous = Allocation->Previous; 490 } 491 492 /* Mark the segment as deleted */ 493 494 ACPI_MEMSET (&Allocation->UserSpace, 0xEA, Allocation->Size); 495 496 ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Freeing size 0%X\n", 497 Allocation->Size)); 498 499 Status = AcpiUtReleaseMutex (ACPI_MTX_MEMORY); 500 return_ACPI_STATUS (Status); 501 } 502 503 504 /******************************************************************************* 505 * 506 * FUNCTION: AcpiUtDumpAllocationInfo 507 * 508 * PARAMETERS: 509 * 510 * RETURN: None 511 * 512 * DESCRIPTION: Print some info about the outstanding allocations. 513 * 514 ******************************************************************************/ 515 516 void 517 AcpiUtDumpAllocationInfo ( 518 void) 519 { 520 /* 521 ACPI_MEMORY_LIST *MemList; 522 */ 523 524 ACPI_FUNCTION_TRACE (UtDumpAllocationInfo); 525 526 /* 527 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, 528 ("%30s: %4d (%3d Kb)\n", "Current allocations", 529 MemList->CurrentCount, 530 ROUND_UP_TO_1K (MemList->CurrentSize))); 531 532 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, 533 ("%30s: %4d (%3d Kb)\n", "Max concurrent allocations", 534 MemList->MaxConcurrentCount, 535 ROUND_UP_TO_1K (MemList->MaxConcurrentSize))); 536 537 538 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, 539 ("%30s: %4d (%3d Kb)\n", "Total (all) internal objects", 540 RunningObjectCount, 541 ROUND_UP_TO_1K (RunningObjectSize))); 542 543 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, 544 ("%30s: %4d (%3d Kb)\n", "Total (all) allocations", 545 RunningAllocCount, 546 ROUND_UP_TO_1K (RunningAllocSize))); 547 548 549 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, 550 ("%30s: %4d (%3d Kb)\n", "Current Nodes", 551 AcpiGbl_CurrentNodeCount, 552 ROUND_UP_TO_1K (AcpiGbl_CurrentNodeSize))); 553 554 ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, 555 ("%30s: %4d (%3d Kb)\n", "Max Nodes", 556 AcpiGbl_MaxConcurrentNodeCount, 557 ROUND_UP_TO_1K ((AcpiGbl_MaxConcurrentNodeCount * 558 sizeof (ACPI_NAMESPACE_NODE))))); 559 */ 560 return_VOID; 561 } 562 563 564 /******************************************************************************* 565 * 566 * FUNCTION: AcpiUtDumpAllocations 567 * 568 * PARAMETERS: Component - Component(s) to dump info for. 569 * Module - Module to dump info for. NULL means all. 570 * 571 * RETURN: None 572 * 573 * DESCRIPTION: Print a list of all outstanding allocations. 574 * 575 ******************************************************************************/ 576 577 void 578 AcpiUtDumpAllocations ( 579 UINT32 Component, 580 const char *Module) 581 { 582 ACPI_DEBUG_MEM_BLOCK *Element; 583 ACPI_DESCRIPTOR *Descriptor; 584 UINT32 NumOutstanding = 0; 585 UINT8 DescriptorType; 586 587 588 ACPI_FUNCTION_TRACE (UtDumpAllocations); 589 590 591 if (AcpiGbl_DisableMemTracking) 592 { 593 return; 594 } 595 596 /* 597 * Walk the allocation list. 598 */ 599 if (ACPI_FAILURE (AcpiUtAcquireMutex (ACPI_MTX_MEMORY))) 600 { 601 return; 602 } 603 604 Element = AcpiGbl_GlobalList->ListHead; 605 while (Element) 606 { 607 if ((Element->Component & Component) && 608 ((Module == NULL) || (0 == ACPI_STRCMP (Module, Element->Module)))) 609 { 610 Descriptor = ACPI_CAST_PTR (ACPI_DESCRIPTOR, &Element->UserSpace); 611 612 if (Element->Size < sizeof (ACPI_COMMON_DESCRIPTOR)) 613 { 614 AcpiOsPrintf ("%p Length 0x%04X %9.9s-%u " 615 "[Not a Descriptor - too small]\n", 616 Descriptor, Element->Size, Element->Module, 617 Element->Line); 618 } 619 else 620 { 621 /* Ignore allocated objects that are in a cache */ 622 623 if (ACPI_GET_DESCRIPTOR_TYPE (Descriptor) != ACPI_DESC_TYPE_CACHED) 624 { 625 AcpiOsPrintf ("%p Length 0x%04X %9.9s-%u [%s] ", 626 Descriptor, Element->Size, Element->Module, 627 Element->Line, AcpiUtGetDescriptorName (Descriptor)); 628 629 /* Validate the descriptor type using Type field and length */ 630 631 DescriptorType = 0; /* Not a valid descriptor type */ 632 633 switch (ACPI_GET_DESCRIPTOR_TYPE (Descriptor)) 634 { 635 case ACPI_DESC_TYPE_OPERAND: 636 if (Element->Size == sizeof (ACPI_DESC_TYPE_OPERAND)) 637 { 638 DescriptorType = ACPI_DESC_TYPE_OPERAND; 639 } 640 break; 641 642 case ACPI_DESC_TYPE_PARSER: 643 if (Element->Size == sizeof (ACPI_DESC_TYPE_PARSER)) 644 { 645 DescriptorType = ACPI_DESC_TYPE_PARSER; 646 } 647 break; 648 649 case ACPI_DESC_TYPE_NAMED: 650 if (Element->Size == sizeof (ACPI_DESC_TYPE_NAMED)) 651 { 652 DescriptorType = ACPI_DESC_TYPE_NAMED; 653 } 654 break; 655 656 default: 657 break; 658 } 659 660 /* Display additional info for the major descriptor types */ 661 662 switch (DescriptorType) 663 { 664 case ACPI_DESC_TYPE_OPERAND: 665 AcpiOsPrintf ("%12.12s RefCount 0x%04X\n", 666 AcpiUtGetTypeName (Descriptor->Object.Common.Type), 667 Descriptor->Object.Common.ReferenceCount); 668 break; 669 670 case ACPI_DESC_TYPE_PARSER: 671 AcpiOsPrintf ("AmlOpcode 0x%04hX\n", 672 Descriptor->Op.Asl.AmlOpcode); 673 break; 674 675 case ACPI_DESC_TYPE_NAMED: 676 AcpiOsPrintf ("%4.4s\n", 677 AcpiUtGetNodeName (&Descriptor->Node)); 678 break; 679 680 default: 681 AcpiOsPrintf ( "\n"); 682 break; 683 } 684 } 685 } 686 687 NumOutstanding++; 688 } 689 690 Element = Element->Next; 691 } 692 693 (void) AcpiUtReleaseMutex (ACPI_MTX_MEMORY); 694 695 /* Print summary */ 696 697 if (!NumOutstanding) 698 { 699 ACPI_INFO ((AE_INFO, "No outstanding allocations")); 700 } 701 else 702 { 703 ACPI_ERROR ((AE_INFO, "%u(0x%X) Outstanding allocations", 704 NumOutstanding, NumOutstanding)); 705 } 706 707 return_VOID; 708 } 709 710 #endif /* ACPI_DBG_TRACK_ALLOCATIONS */ 711