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
acpi_ut_create_list(const char * list_name,u16 object_size,struct acpi_memory_list ** return_cache)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  
acpi_ut_allocate_and_track(acpi_size size,u32 component,const char * module,u32 line)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  
acpi_ut_allocate_zeroed_and_track(acpi_size size,u32 component,const char * module,u32 line)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
acpi_ut_free_and_track(void * allocation,u32 component,const char * module,u32 line)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  
acpi_ut_find_allocation(struct acpi_debug_mem_block * allocation)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
acpi_ut_track_allocation(struct acpi_debug_mem_block * allocation,acpi_size size,u8 alloc_type,u32 component,const char * module,u32 line)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
acpi_ut_remove_allocation(struct acpi_debug_mem_block * allocation,u32 component,const char * module,u32 line)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  
acpi_ut_dump_allocation_info(void)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  
acpi_ut_dump_allocations(u32 component,const char * module)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