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_PARAMLIST;
466         }
467 
468         /*
469          * A Zero predicate indicates the possibility of one or more
470          * External() opcodes within the If() block.
471          */
472         if (NextOp->Common.AmlOpcode == AML_ZERO_OP)
473         {
474             NextOp2 = NextOp->Common.Next;
475 
476             if (NextOp2 &&
477                 (NextOp2->Common.AmlOpcode == AML_EXTERNAL_OP))
478             {
479                 /* Ignore the If 0 block and all children */
480 
481                 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
482                 return (AE_CTRL_DEPTH);
483             }
484         }
485     }
486 
487     /* Level 0 is at the Definition Block level */
488 
489     if (Level == 0)
490     {
491         /* In verbose mode, print the AML offset, opcode and depth count */
492 
493         if (Info->WalkState)
494         {
495             AmlOffset = (UINT32) ACPI_PTR_DIFF (Op->Common.Aml,
496                 Info->WalkState->ParserState.AmlStart);
497             if (AcpiGbl_DmOpt_Verbose)
498             {
499                 AcpiOsPrintf (DB_FULL_OP_INFO,
500                     (Info->WalkState->MethodNode ?
501                         Info->WalkState->MethodNode->Name.Ascii : "   "),
502                     AmlOffset, (UINT32) Op->Common.AmlOpcode);
503             }
504         }
505 
506         if (Op->Common.AmlOpcode == AML_SCOPE_OP)
507         {
508             /* This is the beginning of the Definition Block */
509 
510             AcpiOsPrintf ("{\n");
511 
512             /* Emit all External() declarations here */
513 
514             AcpiDmEmitExternals ();
515             return (AE_OK);
516         }
517     }
518     else if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
519          (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) &&
520          (!(Op->Common.DisasmFlags & ACPI_PARSEOP_ELSEIF)) &&
521          (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
522     {
523         /*
524          * This is a first-level element of a term list,
525          * indent a new line
526          */
527         switch (Op->Common.AmlOpcode)
528         {
529         case AML_NOOP_OP:
530             /*
531              * Optionally just ignore this opcode. Some tables use
532              * NoOp opcodes for "padding" out packages that the BIOS
533              * changes dynamically. This can leave hundreds or
534              * thousands of NoOp opcodes that if disassembled,
535              * cannot be compiled because they are syntactically
536              * incorrect.
537              */
538             if (AcpiGbl_IgnoreNoopOperator)
539             {
540                 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
541                 return (AE_OK);
542             }
543 
544             /* Fallthrough */
545 
546         default:
547 
548             AcpiDmIndent (Level);
549             break;
550         }
551 
552         Info->LastLevel = Level;
553         Info->Count = 0;
554     }
555 
556     /*
557      * This is an inexpensive mechanism to try and keep lines from getting
558      * too long. When the limit is hit, start a new line at the previous
559      * indent plus one. A better but more expensive mechanism would be to
560      * keep track of the current column.
561      */
562     Info->Count++;
563     if (Info->Count /* +Info->LastLevel */ > 12)
564     {
565         Info->Count = 0;
566         AcpiOsPrintf ("\n");
567         AcpiDmIndent (Info->LastLevel + 1);
568     }
569 
570     /* If ASL+ is enabled, check for a C-style operator */
571 
572     if (AcpiDmCheckForSymbolicOpcode (Op, Info))
573     {
574         return (AE_OK);
575     }
576 
577     /* Print the opcode name */
578 
579     AcpiDmDisassembleOneOp (NULL, Info, Op);
580 
581     if ((Op->Common.DisasmOpcode == ACPI_DASM_LNOT_PREFIX) ||
582         (Op->Common.AmlOpcode == AML_INT_CONNECTION_OP))
583     {
584         return (AE_OK);
585     }
586 
587     if ((Op->Common.AmlOpcode == AML_NAME_OP) ||
588         (Op->Common.AmlOpcode == AML_RETURN_OP))
589     {
590         Info->Level--;
591     }
592 
593     /* Start the opcode argument list if necessary */
594 
595     if ((OpInfo->Flags & AML_HAS_ARGS) ||
596         (Op->Common.AmlOpcode == AML_EVENT_OP))
597     {
598         /* This opcode has an argument list */
599 
600         if (AcpiDmBlockType (Op) & BLOCK_PAREN)
601         {
602             AcpiOsPrintf (" (");
603         }
604 
605         /* If this is a named opcode, print the associated name value */
606 
607         if (OpInfo->Flags & AML_NAMED)
608         {
609             switch (Op->Common.AmlOpcode)
610             {
611             case AML_ALIAS_OP:
612 
613                 NextOp = AcpiPsGetDepthNext (NULL, Op);
614                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
615                 AcpiDmNamestring (NextOp->Common.Value.Name);
616                 AcpiOsPrintf (", ");
617 
618                 /*lint -fallthrough */
619 
620             default:
621 
622                 Name = AcpiPsGetName (Op);
623                 if (Op->Named.Path)
624                 {
625                     AcpiDmNamestring ((char *) Op->Named.Path);
626                 }
627                 else
628                 {
629                     AcpiDmDumpName (Name);
630                 }
631 
632                 if (Op->Common.AmlOpcode != AML_INT_NAMEDFIELD_OP)
633                 {
634                     if (AcpiGbl_DmOpt_Verbose)
635                     {
636                         (void) AcpiPsDisplayObjectPathname (NULL, Op);
637                     }
638                 }
639                 break;
640             }
641 
642             switch (Op->Common.AmlOpcode)
643             {
644             case AML_METHOD_OP:
645 
646                 AcpiDmMethodFlags (Op);
647                 AcpiOsPrintf (")");
648 
649                 /* Emit description comment for Method() with a predefined ACPI name */
650 
651                 AcpiDmPredefinedDescription (Op);
652                 break;
653 
654             case AML_NAME_OP:
655 
656                 /* Check for _HID and related EISAID() */
657 
658                 AcpiDmCheckForHardwareId (Op);
659                 AcpiOsPrintf (", ");
660                 break;
661 
662             case AML_REGION_OP:
663 
664                 AcpiDmRegionFlags (Op);
665                 break;
666 
667             case AML_POWER_RES_OP:
668 
669                 /* Mark the next two Ops as part of the parameter list */
670 
671                 AcpiOsPrintf (", ");
672                 NextOp = AcpiPsGetDepthNext (NULL, Op);
673                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
674 
675                 NextOp = NextOp->Common.Next;
676                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
677                 return (AE_OK);
678 
679             case AML_PROCESSOR_OP:
680 
681                 /* Mark the next three Ops as part of the parameter list */
682 
683                 AcpiOsPrintf (", ");
684                 NextOp = AcpiPsGetDepthNext (NULL, Op);
685                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
686 
687                 NextOp = NextOp->Common.Next;
688                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
689 
690                 NextOp = NextOp->Common.Next;
691                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
692                 return (AE_OK);
693 
694             case AML_MUTEX_OP:
695             case AML_DATA_REGION_OP:
696 
697                 AcpiOsPrintf (", ");
698                 return (AE_OK);
699 
700             case AML_EVENT_OP:
701             case AML_ALIAS_OP:
702 
703                 return (AE_OK);
704 
705             case AML_SCOPE_OP:
706             case AML_DEVICE_OP:
707             case AML_THERMAL_ZONE_OP:
708 
709                 AcpiOsPrintf (")");
710                 break;
711 
712             default:
713 
714                 AcpiOsPrintf ("*** Unhandled named opcode %X\n",
715                     Op->Common.AmlOpcode);
716                 break;
717             }
718         }
719 
720         else switch (Op->Common.AmlOpcode)
721         {
722         case AML_FIELD_OP:
723         case AML_BANK_FIELD_OP:
724         case AML_INDEX_FIELD_OP:
725 
726             Info->BitOffset = 0;
727 
728             /* Name of the parent OperationRegion */
729 
730             NextOp = AcpiPsGetDepthNext (NULL, Op);
731             AcpiDmNamestring (NextOp->Common.Value.Name);
732             AcpiOsPrintf (", ");
733             NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
734 
735             switch (Op->Common.AmlOpcode)
736             {
737             case AML_BANK_FIELD_OP:
738 
739                 /* Namestring - Bank Name */
740 
741                 NextOp = AcpiPsGetDepthNext (NULL, NextOp);
742                 AcpiDmNamestring (NextOp->Common.Value.Name);
743                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
744                 AcpiOsPrintf (", ");
745 
746                 /*
747                  * Bank Value. This is a TermArg in the middle of the parameter
748                  * list, must handle it here.
749                  *
750                  * Disassemble the TermArg parse tree. ACPI_PARSEOP_PARAMLIST
751                  * eliminates newline in the output.
752                  */
753                 NextOp = NextOp->Common.Next;
754 
755                 Info->Flags = ACPI_PARSEOP_PARAMLIST;
756                 AcpiDmWalkParseTree (NextOp, AcpiDmDescendingOp,
757                     AcpiDmAscendingOp, Info);
758                 Info->Flags = 0;
759                 Info->Level = Level;
760 
761                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
762                 AcpiOsPrintf (", ");
763                 break;
764 
765             case AML_INDEX_FIELD_OP:
766 
767                 /* Namestring - Data Name */
768 
769                 NextOp = AcpiPsGetDepthNext (NULL, NextOp);
770                 AcpiDmNamestring (NextOp->Common.Value.Name);
771                 AcpiOsPrintf (", ");
772                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
773                 break;
774 
775             default:
776 
777                 break;
778             }
779 
780             AcpiDmFieldFlags (NextOp);
781             break;
782 
783         case AML_BUFFER_OP:
784 
785             /* The next op is the size parameter */
786 
787             NextOp = AcpiPsGetDepthNext (NULL, Op);
788             if (!NextOp)
789             {
790                 /* Single-step support */
791 
792                 return (AE_OK);
793             }
794 
795             if (Op->Common.DisasmOpcode == ACPI_DASM_RESOURCE)
796             {
797                 /*
798                  * We have a resource list. Don't need to output
799                  * the buffer size Op. Open up a new block
800                  */
801                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
802                 NextOp = NextOp->Common.Next;
803                 AcpiOsPrintf (")");
804 
805                 /* Emit description comment for Name() with a predefined ACPI name */
806 
807                 AcpiDmPredefinedDescription (Op->Asl.Parent);
808 
809                 AcpiOsPrintf ("\n");
810                 AcpiDmIndent (Info->Level);
811                 AcpiOsPrintf ("{\n");
812                 return (AE_OK);
813             }
814 
815             /* Normal Buffer, mark size as in the parameter list */
816 
817             NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
818             return (AE_OK);
819 
820         case AML_IF_OP:
821         case AML_VAR_PACKAGE_OP:
822         case AML_WHILE_OP:
823 
824             /* The next op is the size or predicate parameter */
825 
826             NextOp = AcpiPsGetDepthNext (NULL, Op);
827             if (NextOp)
828             {
829                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
830             }
831             return (AE_OK);
832 
833         case AML_PACKAGE_OP:
834 
835             /* The next op is the size parameter */
836 
837             NextOp = AcpiPsGetDepthNext (NULL, Op);
838             if (NextOp)
839             {
840                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
841             }
842             return (AE_OK);
843 
844         case AML_MATCH_OP:
845 
846             AcpiDmMatchOp (Op);
847             break;
848 
849         default:
850 
851             break;
852         }
853 
854         if (AcpiDmBlockType (Op) & BLOCK_BRACE)
855         {
856             AcpiOsPrintf ("\n");
857             AcpiDmIndent (Level);
858             AcpiOsPrintf ("{\n");
859         }
860     }
861 
862     return (AE_OK);
863 }
864 
865 
866 /*******************************************************************************
867  *
868  * FUNCTION:    AcpiDmAscendingOp
869  *
870  * PARAMETERS:  ASL_WALK_CALLBACK
871  *
872  * RETURN:      Status
873  *
874  * DESCRIPTION: Second visitation of a parse object, during ascent of parse
875  *              tree. Close out any parameter lists and complete the opcode.
876  *
877  ******************************************************************************/
878 
879 static ACPI_STATUS
880 AcpiDmAscendingOp (
881     ACPI_PARSE_OBJECT       *Op,
882     UINT32                  Level,
883     void                    *Context)
884 {
885     ACPI_OP_WALK_INFO       *Info = Context;
886     ACPI_PARSE_OBJECT       *ParentOp;
887 
888 
889     if (Op->Common.DisasmFlags & ACPI_PARSEOP_IGNORE)
890     {
891         /* Ignore this op -- it was handled elsewhere */
892 
893         return (AE_OK);
894     }
895 
896     if ((Level == 0) && (Op->Common.AmlOpcode == AML_SCOPE_OP))
897     {
898         /* Indicates the end of the current descriptor block (table) */
899 
900         AcpiOsPrintf ("}\n\n");
901         return (AE_OK);
902     }
903 
904     switch (AcpiDmBlockType (Op))
905     {
906     case BLOCK_PAREN:
907 
908         /* Completed an op that has arguments, add closing paren if needed */
909 
910         AcpiDmCloseOperator (Op);
911 
912         if (Op->Common.AmlOpcode == AML_NAME_OP)
913         {
914             /* Emit description comment for Name() with a predefined ACPI name */
915 
916             AcpiDmPredefinedDescription (Op);
917         }
918         else
919         {
920             /* For Create* operators, attempt to emit resource tag description */
921 
922             AcpiDmFieldPredefinedDescription (Op);
923         }
924 
925         /* Decode Notify() values */
926 
927         if (Op->Common.AmlOpcode == AML_NOTIFY_OP)
928         {
929             AcpiDmNotifyDescription (Op);
930         }
931 
932         AcpiDmDisplayTargetPathname (Op);
933 
934         /* Could be a nested operator, check if comma required */
935 
936         if (!AcpiDmCommaIfListMember (Op))
937         {
938             if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
939                  (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) &&
940                  (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
941             {
942                 /*
943                  * This is a first-level element of a term list
944                  * start a new line
945                  */
946                 if (!(Info->Flags & ACPI_PARSEOP_PARAMLIST))
947                 {
948                     AcpiOsPrintf ("\n");
949                 }
950             }
951         }
952         break;
953 
954     case BLOCK_BRACE:
955     case (BLOCK_BRACE | BLOCK_PAREN):
956 
957         /* Completed an op that has a term list, add closing brace */
958 
959         if (Op->Common.DisasmFlags & ACPI_PARSEOP_EMPTY_TERMLIST)
960         {
961             AcpiOsPrintf ("}");
962         }
963         else
964         {
965             AcpiDmIndent (Level);
966             AcpiOsPrintf ("}");
967         }
968 
969         AcpiDmCommaIfListMember (Op);
970 
971         if (AcpiDmBlockType (Op->Common.Parent) != BLOCK_PAREN)
972         {
973             AcpiOsPrintf ("\n");
974             if (!(Op->Common.DisasmFlags & ACPI_PARSEOP_EMPTY_TERMLIST))
975             {
976                 if ((Op->Common.AmlOpcode == AML_IF_OP)  &&
977                     (Op->Common.Next) &&
978                     (Op->Common.Next->Common.AmlOpcode == AML_ELSE_OP))
979                 {
980                     break;
981                 }
982 
983                 if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
984                     (!Op->Common.Next))
985                 {
986                     break;
987                 }
988                 AcpiOsPrintf ("\n");
989             }
990         }
991         break;
992 
993     case BLOCK_NONE:
994     default:
995 
996         /* Could be a nested operator, check if comma required */
997 
998         if (!AcpiDmCommaIfListMember (Op))
999         {
1000             if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
1001                  (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) &&
1002                  (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
1003             {
1004                 /*
1005                  * This is a first-level element of a term list
1006                  * start a new line
1007                  */
1008                 AcpiOsPrintf ("\n");
1009             }
1010         }
1011         else if (Op->Common.Parent)
1012         {
1013             switch (Op->Common.Parent->Common.AmlOpcode)
1014             {
1015             case AML_PACKAGE_OP:
1016             case AML_VAR_PACKAGE_OP:
1017 
1018                 if (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST))
1019                 {
1020                     AcpiOsPrintf ("\n");
1021                 }
1022                 break;
1023 
1024             default:
1025 
1026                 break;
1027             }
1028         }
1029         break;
1030     }
1031 
1032     if (Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)
1033     {
1034         if ((Op->Common.Next) &&
1035             (Op->Common.Next->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST))
1036         {
1037             return (AE_OK);
1038         }
1039 
1040         /*
1041          * The parent Op is guaranteed to be valid because of the flag
1042          * ACPI_PARSEOP_PARAMLIST -- which means that this op is part of
1043          * a parameter list and thus has a valid parent.
1044          */
1045         ParentOp = Op->Common.Parent;
1046 
1047         /*
1048          * Just completed a parameter node for something like "Buffer (param)".
1049          * Close the paren and open up the term list block with a brace
1050          */
1051         if (Op->Common.Next)
1052         {
1053             AcpiOsPrintf (")");
1054 
1055             /*
1056              * Emit a description comment for a Name() operator that is a
1057              * predefined ACPI name. Must check the grandparent.
1058              */
1059             ParentOp = ParentOp->Common.Parent;
1060             if (ParentOp &&
1061                 (ParentOp->Asl.AmlOpcode == AML_NAME_OP))
1062             {
1063                 AcpiDmPredefinedDescription (ParentOp);
1064             }
1065 
1066             AcpiOsPrintf ("\n");
1067             AcpiDmIndent (Level - 1);
1068             AcpiOsPrintf ("{\n");
1069         }
1070         else
1071         {
1072             ParentOp->Common.DisasmFlags |= ACPI_PARSEOP_EMPTY_TERMLIST;
1073             AcpiOsPrintf (") {");
1074         }
1075     }
1076 
1077     if ((Op->Common.AmlOpcode == AML_NAME_OP) ||
1078         (Op->Common.AmlOpcode == AML_RETURN_OP))
1079     {
1080         Info->Level++;
1081     }
1082 
1083     /*
1084      * For ASL+, check for and emit a C-style symbol. If valid, the
1085      * symbol string has been deferred until after the first operand
1086      */
1087     if (AcpiGbl_CstyleDisassembly)
1088     {
1089         if (Op->Asl.OperatorSymbol)
1090         {
1091             AcpiOsPrintf ("%s", Op->Asl.OperatorSymbol);
1092             Op->Asl.OperatorSymbol = NULL;
1093         }
1094     }
1095 
1096     return (AE_OK);
1097 }
1098 
1099 #endif  /* ACPI_DISASSEMBLER */
1100