dmwalk.c revision 1.1.1.4.2.7 1 /*******************************************************************************
2 *
3 * Module Name: dmwalk - AML disassembly tree walk
4 *
5 ******************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2017, 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 #include "acpi.h"
45 #include "accommon.h"
46 #include "acparser.h"
47 #include "amlcode.h"
48 #include "acdebug.h"
49 #include "acconvert.h"
50
51
52 #define _COMPONENT ACPI_CA_DEBUGGER
53 ACPI_MODULE_NAME ("dmwalk")
54
55
56 #define DB_FULL_OP_INFO "[%4.4s] @%5.5X #%4.4X: "
57
58 /* Stub for non-compiler code */
59
60 #ifndef ACPI_ASL_COMPILER
61 void
62 AcpiDmEmitExternals (
63 void)
64 {
65 return;
66 }
67
68 void
69 AcpiDmEmitExternal (
70 ACPI_PARSE_OBJECT *NameOp,
71 ACPI_PARSE_OBJECT *TypeOp)
72 {
73 return;
74 }
75 #endif
76
77 /* Local prototypes */
78
79 static ACPI_STATUS
80 AcpiDmDescendingOp (
81 ACPI_PARSE_OBJECT *Op,
82 UINT32 Level,
83 void *Context);
84
85 static ACPI_STATUS
86 AcpiDmAscendingOp (
87 ACPI_PARSE_OBJECT *Op,
88 UINT32 Level,
89 void *Context);
90
91
92 /*******************************************************************************
93 *
94 * FUNCTION: AcpiDmDisassemble
95 *
96 * PARAMETERS: WalkState - Current state
97 * Origin - Starting object
98 * NumOpcodes - Max number of opcodes to be displayed
99 *
100 * RETURN: None
101 *
102 * DESCRIPTION: Disassemble parser object and its children. This is the
103 * main entry point of the disassembler.
104 *
105 ******************************************************************************/
106
107 void
108 AcpiDmDisassemble (
109 ACPI_WALK_STATE *WalkState,
110 ACPI_PARSE_OBJECT *Origin,
111 UINT32 NumOpcodes)
112 {
113 ACPI_PARSE_OBJECT *Op = Origin;
114 ACPI_OP_WALK_INFO Info;
115
116
117 if (!Op)
118 {
119 return;
120 }
121
122 memset (&Info, 0, sizeof (ACPI_OP_WALK_INFO));
123 Info.WalkState = WalkState;
124 Info.StartAml = Op->Common.Aml - sizeof (ACPI_TABLE_HEADER);
125 Info.AmlOffset = Op->Common.Aml - Info.StartAml;
126
127 AcpiDmWalkParseTree (Op, AcpiDmDescendingOp, AcpiDmAscendingOp, &Info);
128 return;
129 }
130
131
132 /*******************************************************************************
133 *
134 * FUNCTION: AcpiDmWalkParseTree
135 *
136 * PARAMETERS: Op - Root Op object
137 * DescendingCallback - Called during tree descent
138 * AscendingCallback - Called during tree ascent
139 * Context - To be passed to the callbacks
140 *
141 * RETURN: Status from callback(s)
142 *
143 * DESCRIPTION: Walk the entire parse tree.
144 *
145 ******************************************************************************/
146
147 void
148 AcpiDmWalkParseTree (
149 ACPI_PARSE_OBJECT *Op,
150 ASL_WALK_CALLBACK DescendingCallback,
151 ASL_WALK_CALLBACK AscendingCallback,
152 void *Context)
153 {
154 BOOLEAN NodePreviouslyVisited;
155 ACPI_PARSE_OBJECT *StartOp = Op;
156 ACPI_STATUS Status;
157 ACPI_PARSE_OBJECT *Next;
158 ACPI_OP_WALK_INFO *Info = Context;
159
160
161 Info->Level = 0;
162 NodePreviouslyVisited = FALSE;
163
164 while (Op)
165 {
166 if (NodePreviouslyVisited)
167 {
168 if (AscendingCallback)
169 {
170 Status = AscendingCallback (Op, Info->Level, Context);
171 if (ACPI_FAILURE (Status))
172 {
173 return;
174 }
175 }
176 }
177 else
178 {
179 /* Let the callback process the node */
180
181 Status = DescendingCallback (Op, Info->Level, Context);
182 if (ACPI_SUCCESS (Status))
183 {
184 /* Visit children first, once */
185
186 Next = AcpiPsGetArg (Op, 0);
187 if (Next)
188 {
189 Info->Level++;
190 Op = Next;
191 continue;
192 }
193 }
194 else if (Status != AE_CTRL_DEPTH)
195 {
196 /* Exit immediately on any error */
197
198 return;
199 }
200 }
201
202 /* Terminate walk at start op */
203
204 if (Op == StartOp)
205 {
206 break;
207 }
208
209 /* No more children, re-visit this node */
210
211 if (!NodePreviouslyVisited)
212 {
213 NodePreviouslyVisited = TRUE;
214 continue;
215 }
216
217 /* No more children, visit peers */
218
219 if (Op->Common.Next)
220 {
221 Op = Op->Common.Next;
222 NodePreviouslyVisited = FALSE;
223 }
224 else
225 {
226 /* No peers, re-visit parent */
227
228 if (Info->Level != 0 )
229 {
230 Info->Level--;
231 }
232
233 Op = Op->Common.Parent;
234 NodePreviouslyVisited = TRUE;
235 }
236 }
237
238 /* If we get here, the walk completed with no errors */
239
240 return;
241 }
242
243
244 /*******************************************************************************
245 *
246 * FUNCTION: AcpiDmBlockType
247 *
248 * PARAMETERS: Op - Object to be examined
249 *
250 * RETURN: BlockType - not a block, parens, braces, or even both.
251 *
252 * DESCRIPTION: Type of block for this op (parens or braces)
253 *
254 ******************************************************************************/
255
256 UINT32
257 AcpiDmBlockType (
258 ACPI_PARSE_OBJECT *Op)
259 {
260 const ACPI_OPCODE_INFO *OpInfo;
261
262
263 if (!Op)
264 {
265 return (BLOCK_NONE);
266 }
267
268 switch (Op->Common.AmlOpcode)
269 {
270 case AML_ELSE_OP:
271
272 return (BLOCK_BRACE);
273
274 case AML_METHOD_OP:
275 case AML_DEVICE_OP:
276 case AML_SCOPE_OP:
277 case AML_PROCESSOR_OP:
278 case AML_POWER_RESOURCE_OP:
279 case AML_THERMAL_ZONE_OP:
280 case AML_IF_OP:
281 case AML_WHILE_OP:
282 case AML_FIELD_OP:
283 case AML_INDEX_FIELD_OP:
284 case AML_BANK_FIELD_OP:
285
286 return (BLOCK_PAREN | BLOCK_BRACE);
287
288 case AML_BUFFER_OP:
289
290 if ((Op->Common.DisasmOpcode == ACPI_DASM_UNICODE) ||
291 (Op->Common.DisasmOpcode == ACPI_DASM_UUID) ||
292 (Op->Common.DisasmOpcode == ACPI_DASM_PLD_METHOD))
293 {
294 return (BLOCK_NONE);
295 }
296
297 /*lint -fallthrough */
298
299 case AML_PACKAGE_OP:
300 case AML_VARIABLE_PACKAGE_OP:
301
302 return (BLOCK_PAREN | BLOCK_BRACE);
303
304 case AML_EVENT_OP:
305
306 return (BLOCK_PAREN);
307
308 case AML_INT_METHODCALL_OP:
309
310 if (Op->Common.Parent &&
311 ((Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) ||
312 (Op->Common.Parent->Common.AmlOpcode == AML_VARIABLE_PACKAGE_OP)))
313 {
314 /* This is a reference to a method, not an invocation */
315
316 return (BLOCK_NONE);
317 }
318
319 /*lint -fallthrough */
320
321 default:
322
323 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
324 if (OpInfo->Flags & AML_HAS_ARGS)
325 {
326 return (BLOCK_PAREN);
327 }
328
329 return (BLOCK_NONE);
330 }
331 }
332
333
334 /*******************************************************************************
335 *
336 * FUNCTION: AcpiDmListType
337 *
338 * PARAMETERS: Op - Object to be examined
339 *
340 * RETURN: ListType - has commas or not.
341 *
342 * DESCRIPTION: Type of block for this op (parens or braces)
343 *
344 ******************************************************************************/
345
346 UINT32
347 AcpiDmListType (
348 ACPI_PARSE_OBJECT *Op)
349 {
350 const ACPI_OPCODE_INFO *OpInfo;
351
352
353 if (!Op)
354 {
355 return (BLOCK_NONE);
356 }
357
358 switch (Op->Common.AmlOpcode)
359 {
360
361 case AML_ELSE_OP:
362 case AML_METHOD_OP:
363 case AML_DEVICE_OP:
364 case AML_SCOPE_OP:
365 case AML_POWER_RESOURCE_OP:
366 case AML_PROCESSOR_OP:
367 case AML_THERMAL_ZONE_OP:
368 case AML_IF_OP:
369 case AML_WHILE_OP:
370 case AML_FIELD_OP:
371 case AML_INDEX_FIELD_OP:
372 case AML_BANK_FIELD_OP:
373
374 return (BLOCK_NONE);
375
376 case AML_BUFFER_OP:
377 case AML_PACKAGE_OP:
378 case AML_VARIABLE_PACKAGE_OP:
379
380 return (BLOCK_COMMA_LIST);
381
382 default:
383
384 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
385 if (OpInfo->Flags & AML_HAS_ARGS)
386 {
387 return (BLOCK_COMMA_LIST);
388 }
389
390 return (BLOCK_NONE);
391 }
392 }
393
394
395 /*******************************************************************************
396 *
397 * FUNCTION: AcpiDmDescendingOp
398 *
399 * PARAMETERS: ASL_WALK_CALLBACK
400 *
401 * RETURN: Status
402 *
403 * DESCRIPTION: First visitation of a parse object during tree descent.
404 * Decode opcode name and begin parameter list(s), if any.
405 *
406 ******************************************************************************/
407
408 static ACPI_STATUS
409 AcpiDmDescendingOp (
410 ACPI_PARSE_OBJECT *Op,
411 UINT32 Level,
412 void *Context)
413 {
414 ACPI_OP_WALK_INFO *Info = Context;
415 const ACPI_OPCODE_INFO *OpInfo;
416 UINT32 Name;
417 ACPI_PARSE_OBJECT *NextOp;
418 ACPI_PARSE_OBJECT *NextOp2;
419 UINT32 AmlOffset;
420
421
422 /* Determine which file this parse node is contained in. */
423
424 if (Gbl_CaptureComments)
425 {
426 ASL_CV_LABEL_FILENODE (Op);
427
428 if (Level != 0 && ASL_CV_FILE_HAS_SWITCHED (Op))
429 {
430 ASL_CV_SWITCH_FILES (Level, Op);
431 }
432
433 /* If this parse node has regular comments, print them here. */
434
435 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_STANDARD, NULL, Level);
436 }
437
438 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
439
440 /* Listing support to dump the AML code after the ASL statement */
441
442 if (AcpiGbl_DmOpt_Listing)
443 {
444 /* We only care about these classes of objects */
445
446 if ((OpInfo->Class == AML_CLASS_NAMED_OBJECT) ||
447 (OpInfo->Class == AML_CLASS_CONTROL) ||
448 (OpInfo->Class == AML_CLASS_CREATE) ||
449 ((OpInfo->Class == AML_CLASS_EXECUTE) && (!Op->Common.Next)))
450 {
451 if (AcpiGbl_DmOpt_Listing && Info->PreviousAml)
452 {
453 /* Dump the AML byte code for the previous Op */
454
455 if (Op->Common.Aml > Info->PreviousAml)
456 {
457 AcpiOsPrintf ("\n");
458 AcpiUtDumpBuffer (
459 (Info->StartAml + Info->AmlOffset),
460 (Op->Common.Aml - Info->PreviousAml),
461 DB_BYTE_DISPLAY, Info->AmlOffset);
462 AcpiOsPrintf ("\n");
463 }
464
465 Info->AmlOffset = (Op->Common.Aml - Info->StartAml);
466 }
467
468 Info->PreviousAml = Op->Common.Aml;
469 }
470 }
471
472 if (Op->Common.DisasmFlags & ACPI_PARSEOP_IGNORE)
473 {
474 /* Ignore this op -- it was handled elsewhere */
475
476 return (AE_CTRL_DEPTH);
477 }
478
479 if (AcpiDmIsTempName(Op))
480 {
481 /* Ignore compiler generated temporary names */
482
483 return (AE_CTRL_DEPTH);
484 }
485
486 if (Op->Common.DisasmOpcode == ACPI_DASM_IGNORE_SINGLE)
487 {
488 /* Ignore this op, but not it's children */
489
490 return (AE_OK);
491 }
492
493 if (Op->Common.AmlOpcode == AML_IF_OP)
494 {
495 NextOp = AcpiPsGetDepthNext (NULL, Op);
496 if (NextOp)
497 {
498 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
499
500 /* Don't emit the actual embedded externals unless asked */
501
502 if (!AcpiGbl_DmEmitExternalOpcodes)
503 {
504 /*
505 * A Zero predicate indicates the possibility of one or more
506 * External() opcodes within the If() block.
507 */
508 if (NextOp->Common.AmlOpcode == AML_ZERO_OP)
509 {
510 NextOp2 = NextOp->Common.Next;
511
512 if (NextOp2 &&
513 (NextOp2->Common.AmlOpcode == AML_EXTERNAL_OP))
514 {
515 /* Ignore the If 0 block and all children */
516
517 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
518 return (AE_CTRL_DEPTH);
519 }
520 }
521 }
522 }
523 }
524
525 /* Level 0 is at the Definition Block level */
526
527 if (Level == 0)
528 {
529 /* In verbose mode, print the AML offset, opcode and depth count */
530
531 if (Info->WalkState)
532 {
533 AmlOffset = (UINT32) ACPI_PTR_DIFF (Op->Common.Aml,
534 Info->WalkState->ParserState.AmlStart);
535 if (AcpiGbl_DmOpt_Verbose)
536 {
537 AcpiOsPrintf (DB_FULL_OP_INFO,
538 (Info->WalkState->MethodNode ?
539 Info->WalkState->MethodNode->Name.Ascii : " "),
540 AmlOffset, (UINT32) Op->Common.AmlOpcode);
541 }
542 }
543
544 if (Op->Common.AmlOpcode == AML_SCOPE_OP)
545 {
546 /* This is the beginning of the Definition Block */
547
548 AcpiOsPrintf ("{\n");
549
550 /* Emit all External() declarations here */
551
552 if (!AcpiGbl_DmEmitExternalOpcodes)
553 {
554 AcpiDmEmitExternals ();
555 }
556
557 return (AE_OK);
558 }
559 }
560 else if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
561 (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST)) &&
562 (!(Op->Common.DisasmFlags & ACPI_PARSEOP_ELSEIF)) &&
563 (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
564 {
565 /*
566 * This is a first-level element of a term list,
567 * indent a new line
568 */
569 switch (Op->Common.AmlOpcode)
570 {
571 case AML_NOOP_OP:
572 /*
573 * Optionally just ignore this opcode. Some tables use
574 * NoOp opcodes for "padding" out packages that the BIOS
575 * changes dynamically. This can leave hundreds or
576 * thousands of NoOp opcodes that if disassembled,
577 * cannot be compiled because they are syntactically
578 * incorrect.
579 */
580 if (AcpiGbl_IgnoreNoopOperator)
581 {
582 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
583 return (AE_OK);
584 }
585
586 /* Fallthrough */
587
588 default:
589
590 AcpiDmIndent (Level);
591 break;
592 }
593
594 Info->LastLevel = Level;
595 Info->Count = 0;
596 }
597
598 /*
599 * This is an inexpensive mechanism to try and keep lines from getting
600 * too long. When the limit is hit, start a new line at the previous
601 * indent plus one. A better but more expensive mechanism would be to
602 * keep track of the current column.
603 */
604 Info->Count++;
605 if (Info->Count /* +Info->LastLevel */ > 12)
606 {
607 Info->Count = 0;
608 AcpiOsPrintf ("\n");
609 AcpiDmIndent (Info->LastLevel + 1);
610 }
611
612 /* If ASL+ is enabled, check for a C-style operator */
613
614 if (AcpiDmCheckForSymbolicOpcode (Op, Info))
615 {
616 return (AE_OK);
617 }
618
619 /* Print the opcode name */
620
621 AcpiDmDisassembleOneOp (NULL, Info, Op);
622
623 if ((Op->Common.DisasmOpcode == ACPI_DASM_LNOT_PREFIX) ||
624 (Op->Common.AmlOpcode == AML_INT_CONNECTION_OP))
625 {
626 return (AE_OK);
627 }
628
629 if ((Op->Common.AmlOpcode == AML_NAME_OP) ||
630 (Op->Common.AmlOpcode == AML_RETURN_OP))
631 {
632 Info->Level--;
633 }
634
635 if (Op->Common.AmlOpcode == AML_EXTERNAL_OP)
636 {
637 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
638 return (AE_CTRL_DEPTH);
639 }
640
641 /* Start the opcode argument list if necessary */
642
643 if ((OpInfo->Flags & AML_HAS_ARGS) ||
644 (Op->Common.AmlOpcode == AML_EVENT_OP))
645 {
646 /* This opcode has an argument list */
647
648 if (AcpiDmBlockType (Op) & BLOCK_PAREN)
649 {
650 AcpiOsPrintf (" (");
651 if (!(AcpiDmBlockType (Op) & BLOCK_BRACE))
652 {
653 ASL_CV_PRINT_ONE_COMMENT (Op, AMLCOMMENT_INLINE, " ", 0);
654 }
655 }
656
657 /* If this is a named opcode, print the associated name value */
658
659 if (OpInfo->Flags & AML_NAMED)
660 {
661 switch (Op->Common.AmlOpcode)
662 {
663 case AML_ALIAS_OP:
664
665 NextOp = AcpiPsGetDepthNext (NULL, Op);
666 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
667 AcpiDmNamestring (NextOp->Common.Value.Name);
668 AcpiOsPrintf (", ");
669
670 /*lint -fallthrough */
671
672 default:
673
674 Name = AcpiPsGetName (Op);
675 if (Op->Named.Path)
676 {
677 AcpiDmNamestring ((char *) Op->Named.Path);
678 }
679 else
680 {
681 AcpiDmDumpName (Name);
682 }
683
684 if (Op->Common.AmlOpcode != AML_INT_NAMEDFIELD_OP)
685 {
686 if (AcpiGbl_DmOpt_Verbose)
687 {
688 (void) AcpiPsDisplayObjectPathname (NULL, Op);
689 }
690 }
691 break;
692 }
693
694 switch (Op->Common.AmlOpcode)
695 {
696 case AML_METHOD_OP:
697
698 AcpiDmMethodFlags (Op);
699 ASL_CV_CLOSE_PAREN (Op, Level);
700
701 /* Emit description comment for Method() with a predefined ACPI name */
702
703 AcpiDmPredefinedDescription (Op);
704 break;
705
706 case AML_NAME_OP:
707
708 /* Check for _HID and related EISAID() */
709
710 AcpiDmCheckForHardwareId (Op);
711 AcpiOsPrintf (", ");
712 ASL_CV_PRINT_ONE_COMMENT (Op, AML_NAMECOMMENT, NULL, 0);
713 break;
714
715 case AML_REGION_OP:
716
717 AcpiDmRegionFlags (Op);
718 break;
719
720 case AML_POWER_RESOURCE_OP:
721
722 /* Mark the next two Ops as part of the parameter list */
723
724 AcpiOsPrintf (", ");
725 NextOp = AcpiPsGetDepthNext (NULL, Op);
726 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
727
728 NextOp = NextOp->Common.Next;
729 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
730 return (AE_OK);
731
732 case AML_PROCESSOR_OP:
733
734 /* Mark the next three Ops as part of the parameter list */
735
736 AcpiOsPrintf (", ");
737 NextOp = AcpiPsGetDepthNext (NULL, Op);
738 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
739
740 NextOp = NextOp->Common.Next;
741 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
742
743 NextOp = NextOp->Common.Next;
744 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
745 return (AE_OK);
746
747 case AML_MUTEX_OP:
748 case AML_DATA_REGION_OP:
749
750 AcpiOsPrintf (", ");
751 return (AE_OK);
752
753 case AML_EVENT_OP:
754 case AML_ALIAS_OP:
755
756 return (AE_OK);
757
758 case AML_SCOPE_OP:
759 case AML_DEVICE_OP:
760 case AML_THERMAL_ZONE_OP:
761
762 ASL_CV_CLOSE_PAREN (Op, Level);
763 break;
764
765 default:
766
767 AcpiOsPrintf ("*** Unhandled named opcode %X\n",
768 Op->Common.AmlOpcode);
769 break;
770 }
771 }
772
773 else switch (Op->Common.AmlOpcode)
774 {
775 case AML_FIELD_OP:
776 case AML_BANK_FIELD_OP:
777 case AML_INDEX_FIELD_OP:
778
779 Info->BitOffset = 0;
780
781 /* Name of the parent OperationRegion */
782
783 NextOp = AcpiPsGetDepthNext (NULL, Op);
784 AcpiDmNamestring (NextOp->Common.Value.Name);
785 AcpiOsPrintf (", ");
786 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
787
788 switch (Op->Common.AmlOpcode)
789 {
790 case AML_BANK_FIELD_OP:
791
792 /* Namestring - Bank Name */
793
794 NextOp = AcpiPsGetDepthNext (NULL, NextOp);
795 AcpiDmNamestring (NextOp->Common.Value.Name);
796 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
797 AcpiOsPrintf (", ");
798
799 /*
800 * Bank Value. This is a TermArg in the middle of the parameter
801 * list, must handle it here.
802 *
803 * Disassemble the TermArg parse tree. ACPI_PARSEOP_PARAMETER_LIST
804 * eliminates newline in the output.
805 */
806 NextOp = NextOp->Common.Next;
807
808 Info->Flags = ACPI_PARSEOP_PARAMETER_LIST;
809 AcpiDmWalkParseTree (NextOp, AcpiDmDescendingOp,
810 AcpiDmAscendingOp, Info);
811 Info->Flags = 0;
812 Info->Level = Level;
813
814 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
815 AcpiOsPrintf (", ");
816 break;
817
818 case AML_INDEX_FIELD_OP:
819
820 /* Namestring - Data Name */
821
822 NextOp = AcpiPsGetDepthNext (NULL, NextOp);
823 AcpiDmNamestring (NextOp->Common.Value.Name);
824 AcpiOsPrintf (", ");
825 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
826 break;
827
828 default:
829
830 break;
831 }
832
833 AcpiDmFieldFlags (NextOp);
834 break;
835
836 case AML_BUFFER_OP:
837
838 /* The next op is the size parameter */
839
840 NextOp = AcpiPsGetDepthNext (NULL, Op);
841 if (!NextOp)
842 {
843 /* Single-step support */
844
845 return (AE_OK);
846 }
847
848 if (Op->Common.DisasmOpcode == ACPI_DASM_RESOURCE)
849 {
850 /*
851 * We have a resource list. Don't need to output
852 * the buffer size Op. Open up a new block
853 */
854 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
855 NextOp = NextOp->Common.Next;
856 ASL_CV_CLOSE_PAREN (Op, Level);
857
858 /* Emit description comment for Name() with a predefined ACPI name */
859
860 AcpiDmPredefinedDescription (Op->Asl.Parent);
861
862 AcpiOsPrintf ("\n");
863 AcpiDmIndent (Info->Level);
864 AcpiOsPrintf ("{\n");
865 return (AE_OK);
866 }
867
868 /* Normal Buffer, mark size as in the parameter list */
869
870 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
871 return (AE_OK);
872
873 case AML_IF_OP:
874 case AML_VARIABLE_PACKAGE_OP:
875 case AML_WHILE_OP:
876
877 /* The next op is the size or predicate parameter */
878
879 NextOp = AcpiPsGetDepthNext (NULL, Op);
880 if (NextOp)
881 {
882 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
883 }
884 return (AE_OK);
885
886 case AML_PACKAGE_OP:
887
888 /* The next op is the size parameter */
889
890 NextOp = AcpiPsGetDepthNext (NULL, Op);
891 if (NextOp)
892 {
893 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
894 }
895 return (AE_OK);
896
897 case AML_MATCH_OP:
898
899 AcpiDmMatchOp (Op);
900 break;
901
902 default:
903
904 break;
905 }
906
907 if (AcpiDmBlockType (Op) & BLOCK_BRACE)
908 {
909 AcpiOsPrintf ("\n");
910 AcpiDmIndent (Level);
911 AcpiOsPrintf ("{\n");
912 }
913 }
914
915 return (AE_OK);
916 }
917
918
919 /*******************************************************************************
920 *
921 * FUNCTION: AcpiDmAscendingOp
922 *
923 * PARAMETERS: ASL_WALK_CALLBACK
924 *
925 * RETURN: Status
926 *
927 * DESCRIPTION: Second visitation of a parse object, during ascent of parse
928 * tree. Close out any parameter lists and complete the opcode.
929 *
930 ******************************************************************************/
931
932 static ACPI_STATUS
933 AcpiDmAscendingOp (
934 ACPI_PARSE_OBJECT *Op,
935 UINT32 Level,
936 void *Context)
937 {
938 ACPI_OP_WALK_INFO *Info = Context;
939 ACPI_PARSE_OBJECT *ParentOp;
940
941
942 /* Point the Op's filename pointer to the proper file */
943
944 if (Gbl_CaptureComments)
945 {
946 ASL_CV_LABEL_FILENODE (Op);
947
948 /* Switch the output of these files if necessary */
949
950 if (ASL_CV_FILE_HAS_SWITCHED (Op))
951 {
952 ASL_CV_SWITCH_FILES (Level, Op);
953 }
954 }
955
956 if (Op->Common.DisasmFlags & ACPI_PARSEOP_IGNORE ||
957 Op->Common.DisasmOpcode == ACPI_DASM_IGNORE_SINGLE)
958 {
959 /* Ignore this op -- it was handled elsewhere */
960
961 return (AE_OK);
962 }
963
964 if ((Level == 0) && (Op->Common.AmlOpcode == AML_SCOPE_OP))
965 {
966 /* Indicates the end of the current descriptor block (table) */
967
968 ASL_CV_CLOSE_BRACE (Op, Level);
969
970 /* Print any comments that are at the end of the file here */
971
972 if (Gbl_CaptureComments && AcpiGbl_LastListHead)
973 {
974 AcpiOsPrintf ("\n");
975 ASL_CV_PRINT_ONE_COMMENT_LIST (AcpiGbl_LastListHead, 0);
976 }
977 AcpiOsPrintf ("\n\n");
978
979 return (AE_OK);
980 }
981
982 switch (AcpiDmBlockType (Op))
983 {
984 case BLOCK_PAREN:
985
986 /* Completed an op that has arguments, add closing paren if needed */
987
988 AcpiDmCloseOperator (Op);
989
990 if (Op->Common.AmlOpcode == AML_NAME_OP)
991 {
992 /* Emit description comment for Name() with a predefined ACPI name */
993
994 AcpiDmPredefinedDescription (Op);
995 }
996 else
997 {
998 /* For Create* operators, attempt to emit resource tag description */
999
1000 AcpiDmFieldPredefinedDescription (Op);
1001 }
1002
1003 /* Decode Notify() values */
1004
1005 if (Op->Common.AmlOpcode == AML_NOTIFY_OP)
1006 {
1007 AcpiDmNotifyDescription (Op);
1008 }
1009
1010 AcpiDmDisplayTargetPathname (Op);
1011
1012 /* Could be a nested operator, check if comma required */
1013
1014 if (!AcpiDmCommaIfListMember (Op))
1015 {
1016 if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
1017 (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST)) &&
1018 (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
1019 {
1020 /*
1021 * This is a first-level element of a term list
1022 * start a new line
1023 */
1024 if (!(Info->Flags & ACPI_PARSEOP_PARAMETER_LIST))
1025 {
1026 AcpiOsPrintf ("\n");
1027 }
1028 }
1029 }
1030 break;
1031
1032 case BLOCK_BRACE:
1033 case (BLOCK_BRACE | BLOCK_PAREN):
1034
1035 /* Completed an op that has a term list, add closing brace */
1036
1037 if (Op->Common.DisasmFlags & ACPI_PARSEOP_EMPTY_TERMLIST)
1038 {
1039 ASL_CV_CLOSE_BRACE (Op, Level);
1040 }
1041 else
1042 {
1043 AcpiDmIndent (Level);
1044 ASL_CV_CLOSE_BRACE (Op, Level);
1045 }
1046
1047 AcpiDmCommaIfListMember (Op);
1048
1049 if (AcpiDmBlockType (Op->Common.Parent) != BLOCK_PAREN)
1050 {
1051 AcpiOsPrintf ("\n");
1052 if (!(Op->Common.DisasmFlags & ACPI_PARSEOP_EMPTY_TERMLIST))
1053 {
1054 if ((Op->Common.AmlOpcode == AML_IF_OP) &&
1055 (Op->Common.Next) &&
1056 (Op->Common.Next->Common.AmlOpcode == AML_ELSE_OP))
1057 {
1058 break;
1059 }
1060
1061 if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
1062 (!Op->Common.Next))
1063 {
1064 break;
1065 }
1066 AcpiOsPrintf ("\n");
1067 }
1068 }
1069 break;
1070
1071 case BLOCK_NONE:
1072 default:
1073
1074 /* Could be a nested operator, check if comma required */
1075
1076 if (!AcpiDmCommaIfListMember (Op))
1077 {
1078 if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
1079 (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST)) &&
1080 (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
1081 {
1082 /*
1083 * This is a first-level element of a term list
1084 * start a new line
1085 */
1086 AcpiOsPrintf ("\n");
1087 }
1088 }
1089 else if (Op->Common.Parent)
1090 {
1091 switch (Op->Common.Parent->Common.AmlOpcode)
1092 {
1093 case AML_PACKAGE_OP:
1094 case AML_VARIABLE_PACKAGE_OP:
1095
1096 if (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST))
1097 {
1098 AcpiOsPrintf ("\n");
1099 }
1100 break;
1101
1102 default:
1103
1104 break;
1105 }
1106 }
1107 break;
1108 }
1109
1110 if (Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST)
1111 {
1112 if ((Op->Common.Next) &&
1113 (Op->Common.Next->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST))
1114 {
1115 return (AE_OK);
1116 }
1117
1118 /*
1119 * The parent Op is guaranteed to be valid because of the flag
1120 * ACPI_PARSEOP_PARAMETER_LIST -- which means that this op is part of
1121 * a parameter list and thus has a valid parent.
1122 */
1123 ParentOp = Op->Common.Parent;
1124
1125 /*
1126 * Just completed a parameter node for something like "Buffer (param)".
1127 * Close the paren and open up the term list block with a brace.
1128 *
1129 * Switch predicates don't have a Next node but require a closing paren
1130 * and opening brace.
1131 */
1132 if (Op->Common.Next || Op->Common.DisasmOpcode == ACPI_DASM_SWITCH_PREDICATE)
1133 {
1134 ASL_CV_CLOSE_PAREN (Op, Level);
1135
1136 /*
1137 * Emit a description comment for a Name() operator that is a
1138 * predefined ACPI name. Must check the grandparent.
1139 */
1140 ParentOp = ParentOp->Common.Parent;
1141 if (ParentOp &&
1142 (ParentOp->Asl.AmlOpcode == AML_NAME_OP))
1143 {
1144 AcpiDmPredefinedDescription (ParentOp);
1145 }
1146
1147 /* Correct the indentation level for Switch and Case predicates */
1148
1149 if (Op->Common.DisasmOpcode == ACPI_DASM_SWITCH_PREDICATE)
1150 {
1151 --Level;
1152 }
1153
1154 AcpiOsPrintf ("\n");
1155 AcpiDmIndent (Level - 1);
1156 AcpiOsPrintf ("{\n");
1157 }
1158 else
1159 {
1160 ParentOp->Common.DisasmFlags |= ACPI_PARSEOP_EMPTY_TERMLIST;
1161 ASL_CV_CLOSE_PAREN (Op, Level);
1162 AcpiOsPrintf ("{");
1163 }
1164 }
1165
1166 if ((Op->Common.AmlOpcode == AML_NAME_OP) ||
1167 (Op->Common.AmlOpcode == AML_RETURN_OP))
1168 {
1169 Info->Level++;
1170 }
1171
1172 /*
1173 * For ASL+, check for and emit a C-style symbol. If valid, the
1174 * symbol string has been deferred until after the first operand
1175 */
1176 if (AcpiGbl_CstyleDisassembly)
1177 {
1178 if (Op->Asl.OperatorSymbol)
1179 {
1180 AcpiOsPrintf ("%s", Op->Asl.OperatorSymbol);
1181 Op->Asl.OperatorSymbol = NULL;
1182 }
1183 }
1184
1185 return (AE_OK);
1186 }
1187