1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Module Name: nsdump - table dumping routines for debug |
5 | * |
6 | * Copyright (C) 2000 - 2023, Intel Corp. |
7 | * |
8 | *****************************************************************************/ |
9 | |
10 | #include <acpi/acpi.h> |
11 | #include "accommon.h" |
12 | #include "acnamesp.h" |
13 | #include <acpi/acoutput.h> |
14 | |
15 | #define _COMPONENT ACPI_NAMESPACE |
16 | ACPI_MODULE_NAME("nsdump" ) |
17 | |
18 | /* Local prototypes */ |
19 | #ifdef ACPI_OBSOLETE_FUNCTIONS |
20 | void acpi_ns_dump_root_devices(void); |
21 | |
22 | static acpi_status |
23 | acpi_ns_dump_one_device(acpi_handle obj_handle, |
24 | u32 level, void *context, void **return_value); |
25 | #endif |
26 | |
27 | #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) |
28 | |
29 | static acpi_status |
30 | acpi_ns_dump_one_object_path(acpi_handle obj_handle, |
31 | u32 level, void *context, void **return_value); |
32 | |
33 | static acpi_status |
34 | acpi_ns_get_max_depth(acpi_handle obj_handle, |
35 | u32 level, void *context, void **return_value); |
36 | |
37 | /******************************************************************************* |
38 | * |
39 | * FUNCTION: acpi_ns_print_pathname |
40 | * |
41 | * PARAMETERS: num_segments - Number of ACPI name segments |
42 | * pathname - The compressed (internal) path |
43 | * |
44 | * RETURN: None |
45 | * |
46 | * DESCRIPTION: Print an object's full namespace pathname |
47 | * |
48 | ******************************************************************************/ |
49 | |
50 | void acpi_ns_print_pathname(u32 num_segments, const char *pathname) |
51 | { |
52 | u32 i; |
53 | |
54 | ACPI_FUNCTION_NAME(ns_print_pathname); |
55 | |
56 | /* Check if debug output enabled */ |
57 | |
58 | if (!ACPI_IS_DEBUG_ENABLED(ACPI_LV_NAMES, ACPI_NAMESPACE)) { |
59 | return; |
60 | } |
61 | |
62 | /* Print the entire name */ |
63 | |
64 | ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "[" )); |
65 | |
66 | while (num_segments) { |
67 | for (i = 0; i < 4; i++) { |
68 | isprint((int)pathname[i]) ? |
69 | acpi_os_printf(format: "%c" , pathname[i]) : |
70 | acpi_os_printf(format: "?" ); |
71 | } |
72 | |
73 | pathname += ACPI_NAMESEG_SIZE; |
74 | num_segments--; |
75 | if (num_segments) { |
76 | acpi_os_printf(format: "." ); |
77 | } |
78 | } |
79 | |
80 | acpi_os_printf(format: "]\n" ); |
81 | } |
82 | |
83 | #ifdef ACPI_OBSOLETE_FUNCTIONS |
84 | /* Not used at this time, perhaps later */ |
85 | |
86 | /******************************************************************************* |
87 | * |
88 | * FUNCTION: acpi_ns_dump_pathname |
89 | * |
90 | * PARAMETERS: handle - Object |
91 | * msg - Prefix message |
92 | * level - Desired debug level |
93 | * component - Caller's component ID |
94 | * |
95 | * RETURN: None |
96 | * |
97 | * DESCRIPTION: Print an object's full namespace pathname |
98 | * Manages allocation/freeing of a pathname buffer |
99 | * |
100 | ******************************************************************************/ |
101 | |
102 | void |
103 | acpi_ns_dump_pathname(acpi_handle handle, |
104 | const char *msg, u32 level, u32 component) |
105 | { |
106 | |
107 | ACPI_FUNCTION_TRACE(ns_dump_pathname); |
108 | |
109 | /* Do this only if the requested debug level and component are enabled */ |
110 | |
111 | if (!ACPI_IS_DEBUG_ENABLED(level, component)) { |
112 | return_VOID; |
113 | } |
114 | |
115 | /* Convert handle to a full pathname and print it (with supplied message) */ |
116 | |
117 | acpi_ns_print_node_pathname(handle, msg); |
118 | acpi_os_printf("\n" ); |
119 | return_VOID; |
120 | } |
121 | #endif |
122 | |
123 | /******************************************************************************* |
124 | * |
125 | * FUNCTION: acpi_ns_dump_one_object |
126 | * |
127 | * PARAMETERS: obj_handle - Node to be dumped |
128 | * level - Nesting level of the handle |
129 | * context - Passed into walk_namespace |
130 | * return_value - Not used |
131 | * |
132 | * RETURN: Status |
133 | * |
134 | * DESCRIPTION: Dump a single Node |
135 | * This procedure is a user_function called by acpi_ns_walk_namespace. |
136 | * |
137 | ******************************************************************************/ |
138 | |
139 | acpi_status |
140 | acpi_ns_dump_one_object(acpi_handle obj_handle, |
141 | u32 level, void *context, void **return_value) |
142 | { |
143 | struct acpi_walk_info *info = (struct acpi_walk_info *)context; |
144 | struct acpi_namespace_node *this_node; |
145 | union acpi_operand_object *obj_desc = NULL; |
146 | acpi_object_type obj_type; |
147 | acpi_object_type type; |
148 | u32 bytes_to_dump; |
149 | u32 dbg_level; |
150 | u32 i; |
151 | |
152 | ACPI_FUNCTION_NAME(ns_dump_one_object); |
153 | |
154 | /* Is output enabled? */ |
155 | |
156 | if (!(acpi_dbg_level & info->debug_level)) { |
157 | return (AE_OK); |
158 | } |
159 | |
160 | if (!obj_handle) { |
161 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Null object handle\n" )); |
162 | return (AE_OK); |
163 | } |
164 | |
165 | this_node = acpi_ns_validate_handle(handle: obj_handle); |
166 | if (!this_node) { |
167 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid object handle %p\n" , |
168 | obj_handle)); |
169 | return (AE_OK); |
170 | } |
171 | |
172 | type = this_node->type; |
173 | info->count++; |
174 | |
175 | /* Check if the owner matches */ |
176 | |
177 | if ((info->owner_id != ACPI_OWNER_ID_MAX) && |
178 | (info->owner_id != this_node->owner_id)) { |
179 | return (AE_OK); |
180 | } |
181 | |
182 | if (!(info->display_type & ACPI_DISPLAY_SHORT)) { |
183 | |
184 | /* Indent the object according to the level */ |
185 | |
186 | acpi_os_printf(format: "%2d%*s" , (u32) level - 1, (int)level * 2, " " ); |
187 | |
188 | /* Check the node type and name */ |
189 | |
190 | if (type > ACPI_TYPE_LOCAL_MAX) { |
191 | ACPI_WARNING((AE_INFO, |
192 | "Invalid ACPI Object Type 0x%08X" , type)); |
193 | } |
194 | |
195 | acpi_os_printf(format: "%4.4s" , acpi_ut_get_node_name(object: this_node)); |
196 | } |
197 | |
198 | /* Now we can print out the pertinent information */ |
199 | |
200 | acpi_os_printf(format: " %-12s %p %3.3X " , |
201 | acpi_ut_get_type_name(type), this_node, |
202 | this_node->owner_id); |
203 | |
204 | dbg_level = acpi_dbg_level; |
205 | acpi_dbg_level = 0; |
206 | obj_desc = acpi_ns_get_attached_object(node: this_node); |
207 | acpi_dbg_level = dbg_level; |
208 | |
209 | /* Temp nodes are those nodes created by a control method */ |
210 | |
211 | if (this_node->flags & ANOBJ_TEMPORARY) { |
212 | acpi_os_printf(format: "(T) " ); |
213 | } |
214 | |
215 | switch (info->display_type & ACPI_DISPLAY_MASK) { |
216 | case ACPI_DISPLAY_SUMMARY: |
217 | |
218 | if (!obj_desc) { |
219 | |
220 | /* No attached object. Some types should always have an object */ |
221 | |
222 | switch (type) { |
223 | case ACPI_TYPE_INTEGER: |
224 | case ACPI_TYPE_PACKAGE: |
225 | case ACPI_TYPE_BUFFER: |
226 | case ACPI_TYPE_STRING: |
227 | case ACPI_TYPE_METHOD: |
228 | |
229 | acpi_os_printf(format: "<No attached object>" ); |
230 | break; |
231 | |
232 | default: |
233 | |
234 | break; |
235 | } |
236 | |
237 | acpi_os_printf(format: "\n" ); |
238 | return (AE_OK); |
239 | } |
240 | |
241 | switch (type) { |
242 | case ACPI_TYPE_PROCESSOR: |
243 | |
244 | acpi_os_printf(format: "ID %02X Len %02X Addr %8.8X%8.8X\n" , |
245 | obj_desc->processor.proc_id, |
246 | obj_desc->processor.length, |
247 | ACPI_FORMAT_UINT64(obj_desc->processor. |
248 | address)); |
249 | break; |
250 | |
251 | case ACPI_TYPE_DEVICE: |
252 | |
253 | acpi_os_printf(format: "Notify Object: %p\n" , obj_desc); |
254 | break; |
255 | |
256 | case ACPI_TYPE_METHOD: |
257 | |
258 | acpi_os_printf(format: "Args %X Len %.4X Aml %p\n" , |
259 | (u32) obj_desc->method.param_count, |
260 | obj_desc->method.aml_length, |
261 | obj_desc->method.aml_start); |
262 | break; |
263 | |
264 | case ACPI_TYPE_INTEGER: |
265 | |
266 | acpi_os_printf(format: "= %8.8X%8.8X\n" , |
267 | ACPI_FORMAT_UINT64(obj_desc->integer. |
268 | value)); |
269 | break; |
270 | |
271 | case ACPI_TYPE_PACKAGE: |
272 | |
273 | if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { |
274 | acpi_os_printf(format: "Elements %.2X\n" , |
275 | obj_desc->package.count); |
276 | } else { |
277 | acpi_os_printf(format: "[Length not yet evaluated]\n" ); |
278 | } |
279 | break; |
280 | |
281 | case ACPI_TYPE_BUFFER: |
282 | |
283 | if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { |
284 | acpi_os_printf(format: "Len %.2X" , |
285 | obj_desc->buffer.length); |
286 | |
287 | /* Dump some of the buffer */ |
288 | |
289 | if (obj_desc->buffer.length > 0) { |
290 | acpi_os_printf(format: " =" ); |
291 | for (i = 0; |
292 | (i < obj_desc->buffer.length |
293 | && i < 12); i++) { |
294 | acpi_os_printf(format: " %2.2X" , |
295 | obj_desc->buffer. |
296 | pointer[i]); |
297 | } |
298 | } |
299 | acpi_os_printf(format: "\n" ); |
300 | } else { |
301 | acpi_os_printf(format: "[Length not yet evaluated]\n" ); |
302 | } |
303 | break; |
304 | |
305 | case ACPI_TYPE_STRING: |
306 | |
307 | acpi_os_printf(format: "Len %.2X " , obj_desc->string.length); |
308 | acpi_ut_print_string(string: obj_desc->string.pointer, max_length: 80); |
309 | acpi_os_printf(format: "\n" ); |
310 | break; |
311 | |
312 | case ACPI_TYPE_REGION: |
313 | |
314 | acpi_os_printf(format: "[%s]" , |
315 | acpi_ut_get_region_name(space_id: obj_desc->region. |
316 | space_id)); |
317 | if (obj_desc->region.flags & AOPOBJ_DATA_VALID) { |
318 | acpi_os_printf(format: " Addr %8.8X%8.8X Len %.4X\n" , |
319 | ACPI_FORMAT_UINT64(obj_desc-> |
320 | region. |
321 | address), |
322 | obj_desc->region.length); |
323 | } else { |
324 | acpi_os_printf |
325 | (format: " [Address/Length not yet evaluated]\n" ); |
326 | } |
327 | break; |
328 | |
329 | case ACPI_TYPE_LOCAL_REFERENCE: |
330 | |
331 | acpi_os_printf(format: "[%s]\n" , |
332 | acpi_ut_get_reference_name(object: obj_desc)); |
333 | break; |
334 | |
335 | case ACPI_TYPE_BUFFER_FIELD: |
336 | |
337 | if (obj_desc->buffer_field.buffer_obj && |
338 | obj_desc->buffer_field.buffer_obj->buffer.node) { |
339 | acpi_os_printf(format: "Buf [%4.4s]" , |
340 | acpi_ut_get_node_name(object: obj_desc-> |
341 | buffer_field. |
342 | buffer_obj-> |
343 | buffer. |
344 | node)); |
345 | } |
346 | break; |
347 | |
348 | case ACPI_TYPE_LOCAL_REGION_FIELD: |
349 | |
350 | acpi_os_printf(format: "Rgn [%4.4s]" , |
351 | acpi_ut_get_node_name(object: obj_desc-> |
352 | common_field. |
353 | region_obj->region. |
354 | node)); |
355 | break; |
356 | |
357 | case ACPI_TYPE_LOCAL_BANK_FIELD: |
358 | |
359 | acpi_os_printf(format: "Rgn [%4.4s] Bnk [%4.4s]" , |
360 | acpi_ut_get_node_name(object: obj_desc-> |
361 | common_field. |
362 | region_obj->region. |
363 | node), |
364 | acpi_ut_get_node_name(object: obj_desc-> |
365 | bank_field. |
366 | bank_obj-> |
367 | common_field. |
368 | node)); |
369 | break; |
370 | |
371 | case ACPI_TYPE_LOCAL_INDEX_FIELD: |
372 | |
373 | acpi_os_printf(format: "Idx [%4.4s] Dat [%4.4s]" , |
374 | acpi_ut_get_node_name(object: obj_desc-> |
375 | index_field. |
376 | index_obj-> |
377 | common_field.node), |
378 | acpi_ut_get_node_name(object: obj_desc-> |
379 | index_field. |
380 | data_obj-> |
381 | common_field. |
382 | node)); |
383 | break; |
384 | |
385 | case ACPI_TYPE_LOCAL_ALIAS: |
386 | case ACPI_TYPE_LOCAL_METHOD_ALIAS: |
387 | |
388 | acpi_os_printf(format: "Target %4.4s (%p)\n" , |
389 | acpi_ut_get_node_name(object: obj_desc), |
390 | obj_desc); |
391 | break; |
392 | |
393 | default: |
394 | |
395 | acpi_os_printf(format: "Object %p\n" , obj_desc); |
396 | break; |
397 | } |
398 | |
399 | /* Common field handling */ |
400 | |
401 | switch (type) { |
402 | case ACPI_TYPE_BUFFER_FIELD: |
403 | case ACPI_TYPE_LOCAL_REGION_FIELD: |
404 | case ACPI_TYPE_LOCAL_BANK_FIELD: |
405 | case ACPI_TYPE_LOCAL_INDEX_FIELD: |
406 | |
407 | acpi_os_printf(format: " Off %.3X Len %.2X Acc %.2X\n" , |
408 | (obj_desc->common_field. |
409 | base_byte_offset * 8) |
410 | + |
411 | obj_desc->common_field. |
412 | start_field_bit_offset, |
413 | obj_desc->common_field.bit_length, |
414 | obj_desc->common_field. |
415 | access_byte_width); |
416 | break; |
417 | |
418 | default: |
419 | |
420 | break; |
421 | } |
422 | break; |
423 | |
424 | case ACPI_DISPLAY_OBJECTS: |
425 | |
426 | acpi_os_printf(format: "O:%p" , obj_desc); |
427 | if (!obj_desc) { |
428 | |
429 | /* No attached object, we are done */ |
430 | |
431 | acpi_os_printf(format: "\n" ); |
432 | return (AE_OK); |
433 | } |
434 | |
435 | acpi_os_printf(format: "(R%u)" , obj_desc->common.reference_count); |
436 | |
437 | switch (type) { |
438 | case ACPI_TYPE_METHOD: |
439 | |
440 | /* Name is a Method and its AML offset/length are set */ |
441 | |
442 | acpi_os_printf(format: " M:%p-%X\n" , obj_desc->method.aml_start, |
443 | obj_desc->method.aml_length); |
444 | break; |
445 | |
446 | case ACPI_TYPE_INTEGER: |
447 | |
448 | acpi_os_printf(format: " I:%8.8X8.8%X\n" , |
449 | ACPI_FORMAT_UINT64(obj_desc->integer. |
450 | value)); |
451 | break; |
452 | |
453 | case ACPI_TYPE_STRING: |
454 | |
455 | acpi_os_printf(format: " S:%p-%X\n" , obj_desc->string.pointer, |
456 | obj_desc->string.length); |
457 | break; |
458 | |
459 | case ACPI_TYPE_BUFFER: |
460 | |
461 | acpi_os_printf(format: " B:%p-%X\n" , obj_desc->buffer.pointer, |
462 | obj_desc->buffer.length); |
463 | break; |
464 | |
465 | default: |
466 | |
467 | acpi_os_printf(format: "\n" ); |
468 | break; |
469 | } |
470 | break; |
471 | |
472 | default: |
473 | acpi_os_printf(format: "\n" ); |
474 | break; |
475 | } |
476 | |
477 | /* If debug turned off, done */ |
478 | |
479 | if (!(acpi_dbg_level & ACPI_LV_VALUES)) { |
480 | return (AE_OK); |
481 | } |
482 | |
483 | /* If there is an attached object, display it */ |
484 | |
485 | dbg_level = acpi_dbg_level; |
486 | acpi_dbg_level = 0; |
487 | obj_desc = acpi_ns_get_attached_object(node: this_node); |
488 | acpi_dbg_level = dbg_level; |
489 | |
490 | /* Dump attached objects */ |
491 | |
492 | while (obj_desc) { |
493 | obj_type = ACPI_TYPE_INVALID; |
494 | acpi_os_printf(format: "Attached Object %p: " , obj_desc); |
495 | |
496 | /* Decode the type of attached object and dump the contents */ |
497 | |
498 | switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) { |
499 | case ACPI_DESC_TYPE_NAMED: |
500 | |
501 | acpi_os_printf(format: "(Ptr to Node)\n" ); |
502 | bytes_to_dump = sizeof(struct acpi_namespace_node); |
503 | ACPI_DUMP_BUFFER(obj_desc, bytes_to_dump); |
504 | break; |
505 | |
506 | case ACPI_DESC_TYPE_OPERAND: |
507 | |
508 | obj_type = obj_desc->common.type; |
509 | |
510 | if (obj_type > ACPI_TYPE_LOCAL_MAX) { |
511 | acpi_os_printf |
512 | (format: "(Pointer to ACPI Object type %.2X [UNKNOWN])\n" , |
513 | obj_type); |
514 | |
515 | bytes_to_dump = 32; |
516 | } else { |
517 | acpi_os_printf |
518 | (format: "(Pointer to ACPI Object type %.2X [%s])\n" , |
519 | obj_type, acpi_ut_get_type_name(type: obj_type)); |
520 | |
521 | bytes_to_dump = |
522 | sizeof(union acpi_operand_object); |
523 | } |
524 | |
525 | ACPI_DUMP_BUFFER(obj_desc, bytes_to_dump); |
526 | break; |
527 | |
528 | default: |
529 | |
530 | break; |
531 | } |
532 | |
533 | /* If value is NOT an internal object, we are done */ |
534 | |
535 | if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != |
536 | ACPI_DESC_TYPE_OPERAND) { |
537 | goto cleanup; |
538 | } |
539 | |
540 | /* Valid object, get the pointer to next level, if any */ |
541 | |
542 | switch (obj_type) { |
543 | case ACPI_TYPE_BUFFER: |
544 | case ACPI_TYPE_STRING: |
545 | /* |
546 | * NOTE: takes advantage of common fields between string/buffer |
547 | */ |
548 | bytes_to_dump = obj_desc->string.length; |
549 | obj_desc = (void *)obj_desc->string.pointer; |
550 | |
551 | acpi_os_printf(format: "(Buffer/String pointer %p length %X)\n" , |
552 | obj_desc, bytes_to_dump); |
553 | ACPI_DUMP_BUFFER(obj_desc, bytes_to_dump); |
554 | goto cleanup; |
555 | |
556 | case ACPI_TYPE_BUFFER_FIELD: |
557 | |
558 | obj_desc = |
559 | (union acpi_operand_object *)obj_desc->buffer_field. |
560 | buffer_obj; |
561 | break; |
562 | |
563 | case ACPI_TYPE_PACKAGE: |
564 | |
565 | obj_desc = (void *)obj_desc->package.elements; |
566 | break; |
567 | |
568 | case ACPI_TYPE_METHOD: |
569 | |
570 | obj_desc = (void *)obj_desc->method.aml_start; |
571 | break; |
572 | |
573 | case ACPI_TYPE_LOCAL_REGION_FIELD: |
574 | |
575 | obj_desc = (void *)obj_desc->field.region_obj; |
576 | break; |
577 | |
578 | case ACPI_TYPE_LOCAL_BANK_FIELD: |
579 | |
580 | obj_desc = (void *)obj_desc->bank_field.region_obj; |
581 | break; |
582 | |
583 | case ACPI_TYPE_LOCAL_INDEX_FIELD: |
584 | |
585 | obj_desc = (void *)obj_desc->index_field.index_obj; |
586 | break; |
587 | |
588 | default: |
589 | |
590 | goto cleanup; |
591 | } |
592 | } |
593 | |
594 | cleanup: |
595 | acpi_os_printf(format: "\n" ); |
596 | return (AE_OK); |
597 | } |
598 | |
599 | /******************************************************************************* |
600 | * |
601 | * FUNCTION: acpi_ns_dump_objects |
602 | * |
603 | * PARAMETERS: type - Object type to be dumped |
604 | * display_type - 0 or ACPI_DISPLAY_SUMMARY |
605 | * max_depth - Maximum depth of dump. Use ACPI_UINT32_MAX |
606 | * for an effectively unlimited depth. |
607 | * owner_id - Dump only objects owned by this ID. Use |
608 | * ACPI_UINT32_MAX to match all owners. |
609 | * start_handle - Where in namespace to start/end search |
610 | * |
611 | * RETURN: None |
612 | * |
613 | * DESCRIPTION: Dump typed objects within the loaded namespace. Uses |
614 | * acpi_ns_walk_namespace in conjunction with acpi_ns_dump_one_object. |
615 | * |
616 | ******************************************************************************/ |
617 | |
618 | void |
619 | acpi_ns_dump_objects(acpi_object_type type, |
620 | u8 display_type, |
621 | u32 max_depth, |
622 | acpi_owner_id owner_id, acpi_handle start_handle) |
623 | { |
624 | struct acpi_walk_info info; |
625 | acpi_status status; |
626 | |
627 | ACPI_FUNCTION_ENTRY(); |
628 | |
629 | /* |
630 | * Just lock the entire namespace for the duration of the dump. |
631 | * We don't want any changes to the namespace during this time, |
632 | * especially the temporary nodes since we are going to display |
633 | * them also. |
634 | */ |
635 | status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
636 | if (ACPI_FAILURE(status)) { |
637 | acpi_os_printf(format: "Could not acquire namespace mutex\n" ); |
638 | return; |
639 | } |
640 | |
641 | info.count = 0; |
642 | info.debug_level = ACPI_LV_TABLES; |
643 | info.owner_id = owner_id; |
644 | info.display_type = display_type; |
645 | |
646 | (void)acpi_ns_walk_namespace(type, start_object: start_handle, max_depth, |
647 | ACPI_NS_WALK_NO_UNLOCK | |
648 | ACPI_NS_WALK_TEMP_NODES, |
649 | descending_callback: acpi_ns_dump_one_object, NULL, |
650 | context: (void *)&info, NULL); |
651 | |
652 | acpi_os_printf(format: "\nNamespace node count: %u\n\n" , info.count); |
653 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
654 | } |
655 | |
656 | /******************************************************************************* |
657 | * |
658 | * FUNCTION: acpi_ns_dump_one_object_path, acpi_ns_get_max_depth |
659 | * |
660 | * PARAMETERS: obj_handle - Node to be dumped |
661 | * level - Nesting level of the handle |
662 | * context - Passed into walk_namespace |
663 | * return_value - Not used |
664 | * |
665 | * RETURN: Status |
666 | * |
667 | * DESCRIPTION: Dump the full pathname to a namespace object. acp_ns_get_max_depth |
668 | * computes the maximum nesting depth in the namespace tree, in |
669 | * order to simplify formatting in acpi_ns_dump_one_object_path. |
670 | * These procedures are user_functions called by acpi_ns_walk_namespace. |
671 | * |
672 | ******************************************************************************/ |
673 | |
674 | static acpi_status |
675 | acpi_ns_dump_one_object_path(acpi_handle obj_handle, |
676 | u32 level, void *context, void **return_value) |
677 | { |
678 | u32 max_level = *((u32 *)context); |
679 | char *pathname; |
680 | struct acpi_namespace_node *node; |
681 | int path_indent; |
682 | |
683 | if (!obj_handle) { |
684 | return (AE_OK); |
685 | } |
686 | |
687 | node = acpi_ns_validate_handle(handle: obj_handle); |
688 | if (!node) { |
689 | |
690 | /* Ignore bad node during namespace walk */ |
691 | |
692 | return (AE_OK); |
693 | } |
694 | |
695 | pathname = acpi_ns_get_normalized_pathname(node, TRUE); |
696 | |
697 | path_indent = 1; |
698 | if (level <= max_level) { |
699 | path_indent = max_level - level + 1; |
700 | } |
701 | |
702 | acpi_os_printf(format: "%2d%*s%-12s%*s" , |
703 | level, level, " " , acpi_ut_get_type_name(type: node->type), |
704 | path_indent, " " ); |
705 | |
706 | acpi_os_printf(format: "%s\n" , &pathname[1]); |
707 | ACPI_FREE(pathname); |
708 | return (AE_OK); |
709 | } |
710 | |
711 | static acpi_status |
712 | acpi_ns_get_max_depth(acpi_handle obj_handle, |
713 | u32 level, void *context, void **return_value) |
714 | { |
715 | u32 *max_level = (u32 *)context; |
716 | |
717 | if (level > *max_level) { |
718 | *max_level = level; |
719 | } |
720 | return (AE_OK); |
721 | } |
722 | |
723 | /******************************************************************************* |
724 | * |
725 | * FUNCTION: acpi_ns_dump_object_paths |
726 | * |
727 | * PARAMETERS: type - Object type to be dumped |
728 | * display_type - 0 or ACPI_DISPLAY_SUMMARY |
729 | * max_depth - Maximum depth of dump. Use ACPI_UINT32_MAX |
730 | * for an effectively unlimited depth. |
731 | * owner_id - Dump only objects owned by this ID. Use |
732 | * ACPI_UINT32_MAX to match all owners. |
733 | * start_handle - Where in namespace to start/end search |
734 | * |
735 | * RETURN: None |
736 | * |
737 | * DESCRIPTION: Dump full object pathnames within the loaded namespace. Uses |
738 | * acpi_ns_walk_namespace in conjunction with acpi_ns_dump_one_object_path. |
739 | * |
740 | ******************************************************************************/ |
741 | |
742 | void |
743 | acpi_ns_dump_object_paths(acpi_object_type type, |
744 | u8 display_type, |
745 | u32 max_depth, |
746 | acpi_owner_id owner_id, acpi_handle start_handle) |
747 | { |
748 | acpi_status status; |
749 | u32 max_level = 0; |
750 | |
751 | ACPI_FUNCTION_ENTRY(); |
752 | |
753 | /* |
754 | * Just lock the entire namespace for the duration of the dump. |
755 | * We don't want any changes to the namespace during this time, |
756 | * especially the temporary nodes since we are going to display |
757 | * them also. |
758 | */ |
759 | status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
760 | if (ACPI_FAILURE(status)) { |
761 | acpi_os_printf(format: "Could not acquire namespace mutex\n" ); |
762 | return; |
763 | } |
764 | |
765 | /* Get the max depth of the namespace tree, for formatting later */ |
766 | |
767 | (void)acpi_ns_walk_namespace(type, start_object: start_handle, max_depth, |
768 | ACPI_NS_WALK_NO_UNLOCK | |
769 | ACPI_NS_WALK_TEMP_NODES, |
770 | descending_callback: acpi_ns_get_max_depth, NULL, |
771 | context: (void *)&max_level, NULL); |
772 | |
773 | /* Now dump the entire namespace */ |
774 | |
775 | (void)acpi_ns_walk_namespace(type, start_object: start_handle, max_depth, |
776 | ACPI_NS_WALK_NO_UNLOCK | |
777 | ACPI_NS_WALK_TEMP_NODES, |
778 | descending_callback: acpi_ns_dump_one_object_path, NULL, |
779 | context: (void *)&max_level, NULL); |
780 | |
781 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
782 | } |
783 | |
784 | /******************************************************************************* |
785 | * |
786 | * FUNCTION: acpi_ns_dump_entry |
787 | * |
788 | * PARAMETERS: handle - Node to be dumped |
789 | * debug_level - Output level |
790 | * |
791 | * RETURN: None |
792 | * |
793 | * DESCRIPTION: Dump a single Node |
794 | * |
795 | ******************************************************************************/ |
796 | |
797 | void acpi_ns_dump_entry(acpi_handle handle, u32 debug_level) |
798 | { |
799 | struct acpi_walk_info info; |
800 | |
801 | ACPI_FUNCTION_ENTRY(); |
802 | |
803 | info.debug_level = debug_level; |
804 | info.owner_id = ACPI_OWNER_ID_MAX; |
805 | info.display_type = ACPI_DISPLAY_SUMMARY; |
806 | |
807 | (void)acpi_ns_dump_one_object(obj_handle: handle, level: 1, context: &info, NULL); |
808 | } |
809 | |
810 | #ifdef ACPI_ASL_COMPILER |
811 | /******************************************************************************* |
812 | * |
813 | * FUNCTION: acpi_ns_dump_tables |
814 | * |
815 | * PARAMETERS: search_base - Root of subtree to be dumped, or |
816 | * NS_ALL to dump the entire namespace |
817 | * max_depth - Maximum depth of dump. Use INT_MAX |
818 | * for an effectively unlimited depth. |
819 | * |
820 | * RETURN: None |
821 | * |
822 | * DESCRIPTION: Dump the name space, or a portion of it. |
823 | * |
824 | ******************************************************************************/ |
825 | |
826 | void acpi_ns_dump_tables(acpi_handle search_base, u32 max_depth) |
827 | { |
828 | acpi_handle search_handle = search_base; |
829 | |
830 | ACPI_FUNCTION_TRACE(ns_dump_tables); |
831 | |
832 | if (!acpi_gbl_root_node) { |
833 | /* |
834 | * If the name space has not been initialized, |
835 | * there is nothing to dump. |
836 | */ |
837 | ACPI_DEBUG_PRINT((ACPI_DB_TABLES, |
838 | "namespace not initialized!\n" )); |
839 | return_VOID; |
840 | } |
841 | |
842 | if (ACPI_NS_ALL == search_base) { |
843 | |
844 | /* Entire namespace */ |
845 | |
846 | search_handle = acpi_gbl_root_node; |
847 | ACPI_DEBUG_PRINT((ACPI_DB_TABLES, "\\\n" )); |
848 | } |
849 | |
850 | acpi_ns_dump_objects(ACPI_TYPE_ANY, ACPI_DISPLAY_OBJECTS, max_depth, |
851 | ACPI_OWNER_ID_MAX, search_handle); |
852 | return_VOID; |
853 | } |
854 | #endif |
855 | #endif |
856 | |