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