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