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