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