Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6595 | serge | 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 |
||
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 | 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 | /* 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 | |||
188 | void *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 | |||
250 | void |
||
251 | acpi_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 | |||
311 | static 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 | |||
364 | static acpi_status |
||
365 | acpi_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 | 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 | |||
434 | unlock_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 | |||
454 | static acpi_status |
||
455 | acpi_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 | 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 | |||
518 | void 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 | |||
574 | void 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 == 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 */ |