1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /******************************************************************************* |
3 | * |
4 | * Module Name: dbobject - ACPI object decode and display |
5 | * |
6 | ******************************************************************************/ |
7 | |
8 | #include <acpi/acpi.h> |
9 | #include "accommon.h" |
10 | #include "acnamesp.h" |
11 | #include "acdebug.h" |
12 | |
13 | #define _COMPONENT ACPI_CA_DEBUGGER |
14 | ACPI_MODULE_NAME("dbobject" ) |
15 | |
16 | /* Local prototypes */ |
17 | static void acpi_db_decode_node(struct acpi_namespace_node *node); |
18 | |
19 | /******************************************************************************* |
20 | * |
21 | * FUNCTION: acpi_db_dump_method_info |
22 | * |
23 | * PARAMETERS: status - Method execution status |
24 | * walk_state - Current state of the parse tree walk |
25 | * |
26 | * RETURN: None |
27 | * |
28 | * DESCRIPTION: Called when a method has been aborted because of an error. |
29 | * Dumps the method execution stack, and the method locals/args, |
30 | * and disassembles the AML opcode that failed. |
31 | * |
32 | ******************************************************************************/ |
33 | |
34 | void |
35 | acpi_db_dump_method_info(acpi_status status, struct acpi_walk_state *walk_state) |
36 | { |
37 | struct acpi_thread_state *thread; |
38 | struct acpi_namespace_node *node; |
39 | |
40 | node = walk_state->method_node; |
41 | |
42 | /* There are no locals or arguments for the module-level code case */ |
43 | |
44 | if (node == acpi_gbl_root_node) { |
45 | return; |
46 | } |
47 | |
48 | /* Ignore control codes, they are not errors */ |
49 | |
50 | if (ACPI_CNTL_EXCEPTION(status)) { |
51 | return; |
52 | } |
53 | |
54 | /* We may be executing a deferred opcode */ |
55 | |
56 | if (walk_state->deferred_node) { |
57 | acpi_os_printf(format: "Executing subtree for Buffer/Package/Region\n" ); |
58 | return; |
59 | } |
60 | |
61 | /* |
62 | * If there is no Thread, we are not actually executing a method. |
63 | * This can happen when the iASL compiler calls the interpreter |
64 | * to perform constant folding. |
65 | */ |
66 | thread = walk_state->thread; |
67 | if (!thread) { |
68 | return; |
69 | } |
70 | |
71 | /* Display the method locals and arguments */ |
72 | |
73 | acpi_os_printf(format: "\n" ); |
74 | acpi_db_decode_locals(walk_state); |
75 | acpi_os_printf(format: "\n" ); |
76 | acpi_db_decode_arguments(walk_state); |
77 | acpi_os_printf(format: "\n" ); |
78 | } |
79 | |
80 | /******************************************************************************* |
81 | * |
82 | * FUNCTION: acpi_db_decode_internal_object |
83 | * |
84 | * PARAMETERS: obj_desc - Object to be displayed |
85 | * |
86 | * RETURN: None |
87 | * |
88 | * DESCRIPTION: Short display of an internal object. Numbers/Strings/Buffers. |
89 | * |
90 | ******************************************************************************/ |
91 | |
92 | void acpi_db_decode_internal_object(union acpi_operand_object *obj_desc) |
93 | { |
94 | u32 i; |
95 | |
96 | if (!obj_desc) { |
97 | acpi_os_printf(format: " Uninitialized" ); |
98 | return; |
99 | } |
100 | |
101 | if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) { |
102 | acpi_os_printf(format: " %p [%s]" , obj_desc, |
103 | acpi_ut_get_descriptor_name(object: obj_desc)); |
104 | return; |
105 | } |
106 | |
107 | acpi_os_printf(format: " %s" , acpi_ut_get_object_type_name(obj_desc)); |
108 | |
109 | switch (obj_desc->common.type) { |
110 | case ACPI_TYPE_INTEGER: |
111 | |
112 | acpi_os_printf(format: " %8.8X%8.8X" , |
113 | ACPI_FORMAT_UINT64(obj_desc->integer.value)); |
114 | break; |
115 | |
116 | case ACPI_TYPE_STRING: |
117 | |
118 | acpi_os_printf(format: "(%u) \"%.60s" , |
119 | obj_desc->string.length, |
120 | obj_desc->string.pointer); |
121 | |
122 | if (obj_desc->string.length > 60) { |
123 | acpi_os_printf(format: "..." ); |
124 | } else { |
125 | acpi_os_printf(format: "\"" ); |
126 | } |
127 | break; |
128 | |
129 | case ACPI_TYPE_BUFFER: |
130 | |
131 | acpi_os_printf(format: "(%u)" , obj_desc->buffer.length); |
132 | for (i = 0; (i < 8) && (i < obj_desc->buffer.length); i++) { |
133 | acpi_os_printf(format: " %2.2X" , obj_desc->buffer.pointer[i]); |
134 | } |
135 | break; |
136 | |
137 | default: |
138 | |
139 | acpi_os_printf(format: " %p" , obj_desc); |
140 | break; |
141 | } |
142 | } |
143 | |
144 | /******************************************************************************* |
145 | * |
146 | * FUNCTION: acpi_db_decode_node |
147 | * |
148 | * PARAMETERS: node - Object to be displayed |
149 | * |
150 | * RETURN: None |
151 | * |
152 | * DESCRIPTION: Short display of a namespace node |
153 | * |
154 | ******************************************************************************/ |
155 | |
156 | static void acpi_db_decode_node(struct acpi_namespace_node *node) |
157 | { |
158 | |
159 | acpi_os_printf(format: "<Node> Name %4.4s" , |
160 | acpi_ut_get_node_name(object: node)); |
161 | |
162 | if (node->flags & ANOBJ_METHOD_ARG) { |
163 | acpi_os_printf(format: " [Method Arg]" ); |
164 | } |
165 | if (node->flags & ANOBJ_METHOD_LOCAL) { |
166 | acpi_os_printf(format: " [Method Local]" ); |
167 | } |
168 | |
169 | switch (node->type) { |
170 | |
171 | /* These types have no attached object */ |
172 | |
173 | case ACPI_TYPE_DEVICE: |
174 | |
175 | acpi_os_printf(format: " Device" ); |
176 | break; |
177 | |
178 | case ACPI_TYPE_THERMAL: |
179 | |
180 | acpi_os_printf(format: " Thermal Zone" ); |
181 | break; |
182 | |
183 | default: |
184 | |
185 | acpi_db_decode_internal_object(obj_desc: acpi_ns_get_attached_object |
186 | (node)); |
187 | break; |
188 | } |
189 | } |
190 | |
191 | /******************************************************************************* |
192 | * |
193 | * FUNCTION: acpi_db_display_internal_object |
194 | * |
195 | * PARAMETERS: obj_desc - Object to be displayed |
196 | * walk_state - Current walk state |
197 | * |
198 | * RETURN: None |
199 | * |
200 | * DESCRIPTION: Short display of an internal object |
201 | * |
202 | ******************************************************************************/ |
203 | |
204 | void |
205 | acpi_db_display_internal_object(union acpi_operand_object *obj_desc, |
206 | struct acpi_walk_state *walk_state) |
207 | { |
208 | u8 type; |
209 | |
210 | acpi_os_printf(format: "%p " , obj_desc); |
211 | |
212 | if (!obj_desc) { |
213 | acpi_os_printf(format: "<Null Object>\n" ); |
214 | return; |
215 | } |
216 | |
217 | /* Decode the object type */ |
218 | |
219 | switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) { |
220 | case ACPI_DESC_TYPE_PARSER: |
221 | |
222 | acpi_os_printf(format: "<Parser> " ); |
223 | break; |
224 | |
225 | case ACPI_DESC_TYPE_NAMED: |
226 | |
227 | acpi_db_decode_node(node: (struct acpi_namespace_node *)obj_desc); |
228 | break; |
229 | |
230 | case ACPI_DESC_TYPE_OPERAND: |
231 | |
232 | type = obj_desc->common.type; |
233 | if (type > ACPI_TYPE_LOCAL_MAX) { |
234 | acpi_os_printf(format: " Type %X [Invalid Type]" , (u32)type); |
235 | return; |
236 | } |
237 | |
238 | /* Decode the ACPI object type */ |
239 | |
240 | switch (obj_desc->common.type) { |
241 | case ACPI_TYPE_LOCAL_REFERENCE: |
242 | |
243 | acpi_os_printf(format: "[%s] " , |
244 | acpi_ut_get_reference_name(object: obj_desc)); |
245 | |
246 | /* Decode the reference */ |
247 | |
248 | switch (obj_desc->reference.class) { |
249 | case ACPI_REFCLASS_LOCAL: |
250 | |
251 | acpi_os_printf(format: "%X " , |
252 | obj_desc->reference.value); |
253 | if (walk_state) { |
254 | obj_desc = walk_state->local_variables |
255 | [obj_desc->reference.value].object; |
256 | acpi_os_printf(format: "%p" , obj_desc); |
257 | acpi_db_decode_internal_object |
258 | (obj_desc); |
259 | } |
260 | break; |
261 | |
262 | case ACPI_REFCLASS_ARG: |
263 | |
264 | acpi_os_printf(format: "%X " , |
265 | obj_desc->reference.value); |
266 | if (walk_state) { |
267 | obj_desc = walk_state->arguments |
268 | [obj_desc->reference.value].object; |
269 | acpi_os_printf(format: "%p" , obj_desc); |
270 | acpi_db_decode_internal_object |
271 | (obj_desc); |
272 | } |
273 | break; |
274 | |
275 | case ACPI_REFCLASS_INDEX: |
276 | |
277 | switch (obj_desc->reference.target_type) { |
278 | case ACPI_TYPE_BUFFER_FIELD: |
279 | |
280 | acpi_os_printf(format: "%p" , |
281 | obj_desc->reference. |
282 | object); |
283 | acpi_db_decode_internal_object |
284 | (obj_desc: obj_desc->reference.object); |
285 | break; |
286 | |
287 | case ACPI_TYPE_PACKAGE: |
288 | |
289 | acpi_os_printf(format: "%p" , |
290 | obj_desc->reference. |
291 | where); |
292 | if (!obj_desc->reference.where) { |
293 | acpi_os_printf |
294 | (format: " Uninitialized WHERE pointer" ); |
295 | } else { |
296 | acpi_db_decode_internal_object(obj_desc: * |
297 | (obj_desc-> |
298 | reference. |
299 | where)); |
300 | } |
301 | break; |
302 | |
303 | default: |
304 | |
305 | acpi_os_printf |
306 | (format: "Unknown index target type" ); |
307 | break; |
308 | } |
309 | break; |
310 | |
311 | case ACPI_REFCLASS_REFOF: |
312 | |
313 | if (!obj_desc->reference.object) { |
314 | acpi_os_printf |
315 | (format: "Uninitialized reference subobject pointer" ); |
316 | break; |
317 | } |
318 | |
319 | /* Reference can be to a Node or an Operand object */ |
320 | |
321 | switch (ACPI_GET_DESCRIPTOR_TYPE |
322 | (obj_desc->reference.object)) { |
323 | case ACPI_DESC_TYPE_NAMED: |
324 | |
325 | acpi_db_decode_node(node: obj_desc->reference. |
326 | object); |
327 | break; |
328 | |
329 | case ACPI_DESC_TYPE_OPERAND: |
330 | |
331 | acpi_db_decode_internal_object |
332 | (obj_desc: obj_desc->reference.object); |
333 | break; |
334 | |
335 | default: |
336 | break; |
337 | } |
338 | break; |
339 | |
340 | case ACPI_REFCLASS_NAME: |
341 | |
342 | acpi_db_decode_node(node: obj_desc->reference.node); |
343 | break; |
344 | |
345 | case ACPI_REFCLASS_DEBUG: |
346 | case ACPI_REFCLASS_TABLE: |
347 | |
348 | acpi_os_printf(format: "\n" ); |
349 | break; |
350 | |
351 | default: /* Unknown reference class */ |
352 | |
353 | acpi_os_printf(format: "%2.2X\n" , |
354 | obj_desc->reference.class); |
355 | break; |
356 | } |
357 | break; |
358 | |
359 | default: |
360 | |
361 | acpi_os_printf(format: "<Obj> " ); |
362 | acpi_db_decode_internal_object(obj_desc); |
363 | break; |
364 | } |
365 | break; |
366 | |
367 | default: |
368 | |
369 | acpi_os_printf(format: "<Not a valid ACPI Object Descriptor> [%s]" , |
370 | acpi_ut_get_descriptor_name(object: obj_desc)); |
371 | break; |
372 | } |
373 | |
374 | acpi_os_printf(format: "\n" ); |
375 | } |
376 | |
377 | /******************************************************************************* |
378 | * |
379 | * FUNCTION: acpi_db_decode_locals |
380 | * |
381 | * PARAMETERS: walk_state - State for current method |
382 | * |
383 | * RETURN: None |
384 | * |
385 | * DESCRIPTION: Display all locals for the currently running control method |
386 | * |
387 | ******************************************************************************/ |
388 | |
389 | void acpi_db_decode_locals(struct acpi_walk_state *walk_state) |
390 | { |
391 | u32 i; |
392 | union acpi_operand_object *obj_desc; |
393 | struct acpi_namespace_node *node; |
394 | u8 display_locals = FALSE; |
395 | |
396 | node = walk_state->method_node; |
397 | |
398 | /* There are no locals for the module-level code case */ |
399 | |
400 | if (node == acpi_gbl_root_node) { |
401 | return; |
402 | } |
403 | |
404 | if (!node) { |
405 | acpi_os_printf |
406 | (format: "No method node (Executing subtree for buffer or opregion)\n" ); |
407 | return; |
408 | } |
409 | |
410 | if (node->type != ACPI_TYPE_METHOD) { |
411 | acpi_os_printf(format: "Executing subtree for Buffer/Package/Region\n" ); |
412 | return; |
413 | } |
414 | |
415 | /* Are any locals actually set? */ |
416 | |
417 | for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) { |
418 | obj_desc = walk_state->local_variables[i].object; |
419 | if (obj_desc) { |
420 | display_locals = TRUE; |
421 | break; |
422 | } |
423 | } |
424 | |
425 | /* If any are set, only display the ones that are set */ |
426 | |
427 | if (display_locals) { |
428 | acpi_os_printf |
429 | (format: "\nInitialized Local Variables for Method [%4.4s]:\n" , |
430 | acpi_ut_get_node_name(object: node)); |
431 | |
432 | for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) { |
433 | obj_desc = walk_state->local_variables[i].object; |
434 | if (obj_desc) { |
435 | acpi_os_printf(format: " Local%X: " , i); |
436 | acpi_db_display_internal_object(obj_desc, |
437 | walk_state); |
438 | } |
439 | } |
440 | } else { |
441 | acpi_os_printf |
442 | (format: "No Local Variables are initialized for Method [%4.4s]\n" , |
443 | acpi_ut_get_node_name(object: node)); |
444 | } |
445 | } |
446 | |
447 | /******************************************************************************* |
448 | * |
449 | * FUNCTION: acpi_db_decode_arguments |
450 | * |
451 | * PARAMETERS: walk_state - State for current method |
452 | * |
453 | * RETURN: None |
454 | * |
455 | * DESCRIPTION: Display all arguments for the currently running control method |
456 | * |
457 | ******************************************************************************/ |
458 | |
459 | void acpi_db_decode_arguments(struct acpi_walk_state *walk_state) |
460 | { |
461 | u32 i; |
462 | union acpi_operand_object *obj_desc; |
463 | struct acpi_namespace_node *node; |
464 | u8 display_args = FALSE; |
465 | |
466 | node = walk_state->method_node; |
467 | |
468 | /* There are no arguments for the module-level code case */ |
469 | |
470 | if (node == acpi_gbl_root_node) { |
471 | return; |
472 | } |
473 | |
474 | if (!node) { |
475 | acpi_os_printf |
476 | (format: "No method node (Executing subtree for buffer or opregion)\n" ); |
477 | return; |
478 | } |
479 | |
480 | if (node->type != ACPI_TYPE_METHOD) { |
481 | acpi_os_printf(format: "Executing subtree for Buffer/Package/Region\n" ); |
482 | return; |
483 | } |
484 | |
485 | /* Are any arguments actually set? */ |
486 | |
487 | for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) { |
488 | obj_desc = walk_state->arguments[i].object; |
489 | if (obj_desc) { |
490 | display_args = TRUE; |
491 | break; |
492 | } |
493 | } |
494 | |
495 | /* If any are set, only display the ones that are set */ |
496 | |
497 | if (display_args) { |
498 | acpi_os_printf(format: "Initialized Arguments for Method [%4.4s]: " |
499 | "(%X arguments defined for method invocation)\n" , |
500 | acpi_ut_get_node_name(object: node), |
501 | node->object->method.param_count); |
502 | |
503 | for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) { |
504 | obj_desc = walk_state->arguments[i].object; |
505 | if (obj_desc) { |
506 | acpi_os_printf(format: " Arg%u: " , i); |
507 | acpi_db_display_internal_object(obj_desc, |
508 | walk_state); |
509 | } |
510 | } |
511 | } else { |
512 | acpi_os_printf |
513 | (format: "No Arguments are initialized for method [%4.4s]\n" , |
514 | acpi_ut_get_node_name(object: node)); |
515 | } |
516 | } |
517 | |