1 /*******************************************************************************
2  *
3  * Module Name: dmwalk - AML disassembly tree walk
4  *
5  ******************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2015, 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 "acdisasm.h"
49 #include "acdebug.h"
50 
51 
52 #ifdef ACPI_DISASSEMBLER
53 
54 #define _COMPONENT          ACPI_CA_DEBUGGER
55         ACPI_MODULE_NAME    ("dmwalk")
56 
57 
58 #define DB_FULL_OP_INFO     "[%4.4s] @%5.5X #%4.4X:  "
59 
60 /* Stub for non-compiler code */
61 
62 #ifndef ACPI_ASL_COMPILER
63 void
64 AcpiDmEmitExternals (
65     void)
66 {
67     return;
68 }
69 #endif
70 
71 /* Local prototypes */
72 
73 static ACPI_STATUS
74 AcpiDmDescendingOp (
75     ACPI_PARSE_OBJECT       *Op,
76     UINT32                  Level,
77     void                    *Context);
78 
79 static ACPI_STATUS
80 AcpiDmAscendingOp (
81     ACPI_PARSE_OBJECT       *Op,
82     UINT32                  Level,
83     void                    *Context);
84 
85 static UINT32
86 AcpiDmBlockType (
87     ACPI_PARSE_OBJECT       *Op);
88 
89 
90 /*******************************************************************************
91  *
92  * FUNCTION:    AcpiDmDisassemble
93  *
94  * PARAMETERS:  WalkState       - Current state
95  *              Origin          - Starting object
96  *              NumOpcodes      - Max number of opcodes to be displayed
97  *
98  * RETURN:      None
99  *
100  * DESCRIPTION: Disassemble parser object and its children. This is the
101  *              main entry point of the disassembler.
102  *
103  ******************************************************************************/
104 
105 void
106 AcpiDmDisassemble (
107     ACPI_WALK_STATE         *WalkState,
108     ACPI_PARSE_OBJECT       *Origin,
109     UINT32                  NumOpcodes)
110 {
111     ACPI_PARSE_OBJECT       *Op = Origin;
112     ACPI_OP_WALK_INFO       Info;
113 
114 
115     if (!Op)
116     {
117         return;
118     }
119 
120     Info.Flags = 0;
121     Info.Level = 0;
122     Info.Count = 0;
123     Info.WalkState = WalkState;
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     UINT32                  AmlOffset;
416 
417 
418     if (AcpiGbl_DbOpt_Verbose && AcpiGbl_PreviousOp)
419     {
420         /* Dump the entire statement in AML byte code */
421 
422         if (Op->Common.Aml > AcpiGbl_PreviousOp->Common.Aml)
423         {
424             AcpiOsPrintf ("\n");
425             AcpiUtDumpBuffer (AcpiGbl_PreviousOp->Common.Aml,
426                 (Op->Common.Aml - AcpiGbl_PreviousOp->Common.Aml),
427                 DB_BYTE_DISPLAY, 0);
428             AcpiDmIndent (Level);
429         }
430     }
431     AcpiGbl_PreviousOp = Op;
432 
433     if (Op->Common.DisasmFlags & ACPI_PARSEOP_IGNORE)
434     {
435         /* Ignore this op -- it was handled elsewhere */
436 
437         return (AE_CTRL_DEPTH);
438     }
439 
440     /* Level 0 is at the Definition Block level */
441 
442     if (Level == 0)
443     {
444         /* In verbose mode, print the AML offset, opcode and depth count */
445 
446         if (Info->WalkState)
447         {
448             AmlOffset = (UINT32) ACPI_PTR_DIFF (Op->Common.Aml,
449                             Info->WalkState->ParserState.AmlStart);
450             VERBOSE_PRINT ((DB_FULL_OP_INFO,
451                 (Info->WalkState->MethodNode ?
452                     Info->WalkState->MethodNode->Name.Ascii : "   "),
453                 AmlOffset, (UINT32) Op->Common.AmlOpcode));
454         }
455 
456         if (Op->Common.AmlOpcode == AML_SCOPE_OP)
457         {
458             /* This is the beginning of the Definition Block */
459 
460             AcpiOsPrintf ("{\n");
461 
462             /* Emit all External() declarations here */
463 
464             AcpiDmEmitExternals ();
465             return (AE_OK);
466         }
467     }
468     else if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
469              (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) &&
470              (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
471     {
472             /*
473              * This is a first-level element of a term list,
474              * indent a new line
475              */
476             switch (Op->Common.AmlOpcode)
477             {
478             case AML_NOOP_OP:
479                 /*
480                  * Optionally just ignore this opcode. Some tables use
481                  * NoOp opcodes for "padding" out packages that the BIOS
482                  * changes dynamically. This can leave hundreds or
483                  * thousands of NoOp opcodes that if disassembled,
484                  * cannot be compiled because they are syntactically
485                  * incorrect.
486                  */
487                 if (AcpiGbl_IgnoreNoopOperator)
488                 {
489                     Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
490                     return (AE_OK);
491                 }
492 
493                 /* Fallthrough */
494 
495             default:
496 
497                 AcpiDmIndent (Level);
498                 break;
499             }
500 
501             Info->LastLevel = Level;
502             Info->Count = 0;
503     }
504 
505     /*
506      * This is an inexpensive mechanism to try and keep lines from getting
507      * too long. When the limit is hit, start a new line at the previous
508      * indent plus one. A better but more expensive mechanism would be to
509      * keep track of the current column.
510      */
511     Info->Count++;
512     if (Info->Count /* +Info->LastLevel */ > 12)
513     {
514         Info->Count = 0;
515         AcpiOsPrintf ("\n");
516         AcpiDmIndent (Info->LastLevel + 1);
517     }
518 
519     /* If ASL+ is enabled, check for a C-style operator */
520 
521     if (AcpiDmCheckForSymbolicOpcode (Op, Info))
522     {
523         return (AE_OK);
524     }
525 
526     /* Print the opcode name */
527 
528     AcpiDmDisassembleOneOp (NULL, Info, Op);
529 
530     if ((Op->Common.DisasmOpcode == ACPI_DASM_LNOT_PREFIX) ||
531         (Op->Common.AmlOpcode == AML_INT_CONNECTION_OP))
532     {
533         return (AE_OK);
534     }
535 
536     if ((Op->Common.AmlOpcode == AML_NAME_OP) ||
537         (Op->Common.AmlOpcode == AML_RETURN_OP))
538     {
539         Info->Level--;
540     }
541 
542     /* Start the opcode argument list if necessary */
543 
544     OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
545 
546     if ((OpInfo->Flags & AML_HAS_ARGS) ||
547         (Op->Common.AmlOpcode == AML_EVENT_OP))
548     {
549         /* This opcode has an argument list */
550 
551         if (AcpiDmBlockType (Op) & BLOCK_PAREN)
552         {
553             AcpiOsPrintf (" (");
554         }
555 
556         /* If this is a named opcode, print the associated name value */
557 
558         if (OpInfo->Flags & AML_NAMED)
559         {
560             switch (Op->Common.AmlOpcode)
561             {
562             case AML_ALIAS_OP:
563 
564                 NextOp = AcpiPsGetDepthNext (NULL, Op);
565                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
566                 AcpiDmNamestring (NextOp->Common.Value.Name);
567                 AcpiOsPrintf (", ");
568 
569                 /*lint -fallthrough */
570 
571             default:
572 
573                 Name = AcpiPsGetName (Op);
574                 if (Op->Named.Path)
575                 {
576                     AcpiDmNamestring ((char *) Op->Named.Path);
577                 }
578                 else
579                 {
580                     AcpiDmDumpName (Name);
581                 }
582 
583                 if (Op->Common.AmlOpcode != AML_INT_NAMEDFIELD_OP)
584                 {
585                     if (AcpiGbl_DbOpt_Verbose)
586                     {
587                         (void) AcpiPsDisplayObjectPathname (NULL, Op);
588                     }
589                 }
590                 break;
591             }
592 
593             switch (Op->Common.AmlOpcode)
594             {
595             case AML_METHOD_OP:
596 
597                 AcpiDmMethodFlags (Op);
598                 AcpiOsPrintf (")");
599 
600                 /* Emit description comment for Method() with a predefined ACPI name */
601 
602                 AcpiDmPredefinedDescription (Op);
603                 break;
604 
605             case AML_NAME_OP:
606 
607                 /* Check for _HID and related EISAID() */
608 
609                 AcpiDmCheckForHardwareId (Op);
610                 AcpiOsPrintf (", ");
611                 break;
612 
613             case AML_REGION_OP:
614 
615                 AcpiDmRegionFlags (Op);
616                 break;
617 
618             case AML_POWER_RES_OP:
619 
620                 /* Mark the next two Ops as part of the parameter list */
621 
622                 AcpiOsPrintf (", ");
623                 NextOp = AcpiPsGetDepthNext (NULL, Op);
624                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
625 
626                 NextOp = NextOp->Common.Next;
627                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
628                 return (AE_OK);
629 
630             case AML_PROCESSOR_OP:
631 
632                 /* Mark the next three Ops as part of the parameter list */
633 
634                 AcpiOsPrintf (", ");
635                 NextOp = AcpiPsGetDepthNext (NULL, Op);
636                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
637 
638                 NextOp = NextOp->Common.Next;
639                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
640 
641                 NextOp = NextOp->Common.Next;
642                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
643                 return (AE_OK);
644 
645             case AML_MUTEX_OP:
646             case AML_DATA_REGION_OP:
647 
648                 AcpiOsPrintf (", ");
649                 return (AE_OK);
650 
651             case AML_EVENT_OP:
652             case AML_ALIAS_OP:
653 
654                 return (AE_OK);
655 
656             case AML_SCOPE_OP:
657             case AML_DEVICE_OP:
658             case AML_THERMAL_ZONE_OP:
659 
660                 AcpiOsPrintf (")");
661                 break;
662 
663             default:
664 
665                 AcpiOsPrintf ("*** Unhandled named opcode %X\n",
666                     Op->Common.AmlOpcode);
667                 break;
668             }
669         }
670 
671         else switch (Op->Common.AmlOpcode)
672         {
673         case AML_FIELD_OP:
674         case AML_BANK_FIELD_OP:
675         case AML_INDEX_FIELD_OP:
676 
677             Info->BitOffset = 0;
678 
679             /* Name of the parent OperationRegion */
680 
681             NextOp = AcpiPsGetDepthNext (NULL, Op);
682             AcpiDmNamestring (NextOp->Common.Value.Name);
683             AcpiOsPrintf (", ");
684             NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
685 
686             switch (Op->Common.AmlOpcode)
687             {
688             case AML_BANK_FIELD_OP:
689 
690                 /* Namestring - Bank Name */
691 
692                 NextOp = AcpiPsGetDepthNext (NULL, NextOp);
693                 AcpiDmNamestring (NextOp->Common.Value.Name);
694                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
695                 AcpiOsPrintf (", ");
696 
697                 /*
698                  * Bank Value. This is a TermArg in the middle of the parameter
699                  * list, must handle it here.
700                  *
701                  * Disassemble the TermArg parse tree. ACPI_PARSEOP_PARAMLIST
702                  * eliminates newline in the output.
703                  */
704                 NextOp = NextOp->Common.Next;
705 
706                 Info->Flags = ACPI_PARSEOP_PARAMLIST;
707                 AcpiDmWalkParseTree (NextOp, AcpiDmDescendingOp,
708                     AcpiDmAscendingOp, Info);
709                 Info->Flags = 0;
710                 Info->Level = Level;
711 
712                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
713                 AcpiOsPrintf (", ");
714                 break;
715 
716             case AML_INDEX_FIELD_OP:
717 
718                 /* Namestring - Data Name */
719 
720                 NextOp = AcpiPsGetDepthNext (NULL, NextOp);
721                 AcpiDmNamestring (NextOp->Common.Value.Name);
722                 AcpiOsPrintf (", ");
723                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
724                 break;
725 
726             default:
727 
728                 break;
729             }
730 
731             AcpiDmFieldFlags (NextOp);
732             break;
733 
734         case AML_BUFFER_OP:
735 
736             /* The next op is the size parameter */
737 
738             NextOp = AcpiPsGetDepthNext (NULL, Op);
739             if (!NextOp)
740             {
741                 /* Single-step support */
742 
743                 return (AE_OK);
744             }
745 
746             if (Op->Common.DisasmOpcode == ACPI_DASM_RESOURCE)
747             {
748                 /*
749                  * We have a resource list. Don't need to output
750                  * the buffer size Op. Open up a new block
751                  */
752                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
753                 NextOp = NextOp->Common.Next;
754                 AcpiOsPrintf (")");
755 
756                 /* Emit description comment for Name() with a predefined ACPI name */
757 
758                 AcpiDmPredefinedDescription (Op->Asl.Parent);
759 
760                 AcpiOsPrintf ("\n");
761                 AcpiDmIndent (Info->Level);
762                 AcpiOsPrintf ("{\n");
763                 return (AE_OK);
764             }
765 
766             /* Normal Buffer, mark size as in the parameter list */
767 
768             NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
769             return (AE_OK);
770 
771         case AML_VAR_PACKAGE_OP:
772         case AML_IF_OP:
773         case AML_WHILE_OP:
774 
775             /* The next op is the size or predicate parameter */
776 
777             NextOp = AcpiPsGetDepthNext (NULL, Op);
778             if (NextOp)
779             {
780                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
781             }
782             return (AE_OK);
783 
784         case AML_PACKAGE_OP:
785 
786             /* The next op is the size parameter */
787 
788             NextOp = AcpiPsGetDepthNext (NULL, Op);
789             if (NextOp)
790             {
791                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
792             }
793             return (AE_OK);
794 
795         case AML_MATCH_OP:
796 
797             AcpiDmMatchOp (Op);
798             break;
799 
800         default:
801 
802             break;
803         }
804 
805         if (AcpiDmBlockType (Op) & BLOCK_BRACE)
806         {
807             AcpiOsPrintf ("\n");
808             AcpiDmIndent (Level);
809             AcpiOsPrintf ("{\n");
810         }
811     }
812 
813     return (AE_OK);
814 }
815 
816 
817 /*******************************************************************************
818  *
819  * FUNCTION:    AcpiDmAscendingOp
820  *
821  * PARAMETERS:  ASL_WALK_CALLBACK
822  *
823  * RETURN:      Status
824  *
825  * DESCRIPTION: Second visitation of a parse object, during ascent of parse
826  *              tree. Close out any parameter lists and complete the opcode.
827  *
828  ******************************************************************************/
829 
830 static ACPI_STATUS
831 AcpiDmAscendingOp (
832     ACPI_PARSE_OBJECT       *Op,
833     UINT32                  Level,
834     void                    *Context)
835 {
836     ACPI_OP_WALK_INFO       *Info = Context;
837     ACPI_PARSE_OBJECT       *ParentOp;
838 
839 
840     if (Op->Common.DisasmFlags & ACPI_PARSEOP_IGNORE)
841     {
842         /* Ignore this op -- it was handled elsewhere */
843 
844         return (AE_OK);
845     }
846 
847     if ((Level == 0) && (Op->Common.AmlOpcode == AML_SCOPE_OP))
848     {
849         /* Indicates the end of the current descriptor block (table) */
850 
851         AcpiOsPrintf ("}\n\n");
852         return (AE_OK);
853     }
854 
855     switch (AcpiDmBlockType (Op))
856     {
857     case BLOCK_PAREN:
858 
859         /* Completed an op that has arguments, add closing paren if needed */
860 
861         AcpiDmCloseOperator (Op);
862 
863         if (Op->Common.AmlOpcode == AML_NAME_OP)
864         {
865             /* Emit description comment for Name() with a predefined ACPI name */
866 
867             AcpiDmPredefinedDescription (Op);
868         }
869         else
870         {
871             /* For Create* operators, attempt to emit resource tag description */
872 
873             AcpiDmFieldPredefinedDescription (Op);
874         }
875 
876         /* Decode Notify() values */
877 
878         if (Op->Common.AmlOpcode == AML_NOTIFY_OP)
879         {
880             AcpiDmNotifyDescription (Op);
881         }
882 
883         AcpiDmDisplayTargetPathname (Op);
884 
885         /* Could be a nested operator, check if comma required */
886 
887         if (!AcpiDmCommaIfListMember (Op))
888         {
889             if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
890                      (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) &&
891                      (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
892             {
893                 /*
894                  * This is a first-level element of a term list
895                  * start a new line
896                  */
897                 if (!(Info->Flags & ACPI_PARSEOP_PARAMLIST))
898                 {
899                     AcpiOsPrintf ("\n");
900                 }
901             }
902         }
903         break;
904 
905     case BLOCK_BRACE:
906     case (BLOCK_BRACE | BLOCK_PAREN):
907 
908         /* Completed an op that has a term list, add closing brace */
909 
910         if (Op->Common.DisasmFlags & ACPI_PARSEOP_EMPTY_TERMLIST)
911         {
912             AcpiOsPrintf ("}");
913         }
914         else
915         {
916             AcpiDmIndent (Level);
917             AcpiOsPrintf ("}");
918         }
919 
920         AcpiDmCommaIfListMember (Op);
921 
922         if (AcpiDmBlockType (Op->Common.Parent) != BLOCK_PAREN)
923         {
924             AcpiOsPrintf ("\n");
925             if (!(Op->Common.DisasmFlags & ACPI_PARSEOP_EMPTY_TERMLIST))
926             {
927                 if ((Op->Common.AmlOpcode == AML_IF_OP)  &&
928                     (Op->Common.Next) &&
929                     (Op->Common.Next->Common.AmlOpcode == AML_ELSE_OP))
930                 {
931                     break;
932                 }
933 
934                 if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
935                     (!Op->Common.Next))
936                 {
937                     break;
938                 }
939                 AcpiOsPrintf ("\n");
940             }
941         }
942         break;
943 
944     case BLOCK_NONE:
945     default:
946 
947         /* Could be a nested operator, check if comma required */
948 
949         if (!AcpiDmCommaIfListMember (Op))
950         {
951             if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
952                      (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) &&
953                      (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
954             {
955                 /*
956                  * This is a first-level element of a term list
957                  * start a new line
958                  */
959                 AcpiOsPrintf ("\n");
960             }
961         }
962         else if (Op->Common.Parent)
963         {
964             switch (Op->Common.Parent->Common.AmlOpcode)
965             {
966             case AML_PACKAGE_OP:
967             case AML_VAR_PACKAGE_OP:
968 
969                 if (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST))
970                 {
971                     AcpiOsPrintf ("\n");
972                 }
973                 break;
974 
975             default:
976 
977                 break;
978             }
979         }
980         break;
981     }
982 
983     if (Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)
984     {
985         if ((Op->Common.Next) &&
986             (Op->Common.Next->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST))
987         {
988             return (AE_OK);
989         }
990 
991         /*
992          * The parent Op is guaranteed to be valid because of the flag
993          * ACPI_PARSEOP_PARAMLIST -- which means that this op is part of
994          * a parameter list and thus has a valid parent.
995          */
996         ParentOp = Op->Common.Parent;
997 
998         /*
999          * Just completed a parameter node for something like "Buffer (param)".
1000          * Close the paren and open up the term list block with a brace
1001          */
1002         if (Op->Common.Next)
1003         {
1004             AcpiOsPrintf (")");
1005 
1006             /*
1007              * Emit a description comment for a Name() operator that is a
1008              * predefined ACPI name. Must check the grandparent.
1009              */
1010             ParentOp = ParentOp->Common.Parent;
1011             if (ParentOp &&
1012                 (ParentOp->Asl.AmlOpcode == AML_NAME_OP))
1013             {
1014                 AcpiDmPredefinedDescription (ParentOp);
1015             }
1016 
1017             AcpiOsPrintf ("\n");
1018             AcpiDmIndent (Level - 1);
1019             AcpiOsPrintf ("{\n");
1020         }
1021         else
1022         {
1023             ParentOp->Common.DisasmFlags |= ACPI_PARSEOP_EMPTY_TERMLIST;
1024             AcpiOsPrintf (") {");
1025         }
1026     }
1027 
1028     if ((Op->Common.AmlOpcode == AML_NAME_OP) ||
1029         (Op->Common.AmlOpcode == AML_RETURN_OP))
1030     {
1031         Info->Level++;
1032     }
1033 
1034     /*
1035      * For ASL+, check for and emit a C-style symbol. If valid, the
1036      * symbol string has been deferred until after the first operand
1037      */
1038     if (AcpiGbl_CstyleDisassembly)
1039     {
1040         if (Op->Asl.OperatorSymbol)
1041         {
1042             AcpiOsPrintf ("%s", Op->Asl.OperatorSymbol);
1043             Op->Asl.OperatorSymbol = NULL;
1044         }
1045     }
1046 
1047     return (AE_OK);
1048 }
1049 
1050 #endif  /* ACPI_DISASSEMBLER */
1051