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