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