1 /******************************************************************************
3 * Module Name: adwalk - Application-level disassembler parse tree walk routines
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2011, Intel Corp.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
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.
45 #include <contrib/dev/acpica/include/acpi.h>
46 #include <contrib/dev/acpica/include/accommon.h>
47 #include <contrib/dev/acpica/include/acparser.h>
48 #include <contrib/dev/acpica/include/amlcode.h>
49 #include <contrib/dev/acpica/include/acdisasm.h>
50 #include <contrib/dev/acpica/include/acdispat.h>
51 #include <contrib/dev/acpica/include/acnamesp.h>
52 #include <contrib/dev/acpica/include/acapps.h>
55 #define _COMPONENT ACPI_TOOLS
56 ACPI_MODULE_NAME ("adwalk")
59 * aslmap - opcode mappings and reserved method names
62 AslMapNamedOpcodeToDataType (
65 /* Local prototypes */
68 AcpiDmFindOrphanDescending (
69 ACPI_PARSE_OBJECT *Op,
74 AcpiDmDumpDescending (
75 ACPI_PARSE_OBJECT *Op,
80 AcpiDmXrefDescendingOp (
81 ACPI_PARSE_OBJECT *Op,
86 AcpiDmCommonAscendingOp (
87 ACPI_PARSE_OBJECT *Op,
92 AcpiDmLoadDescendingOp (
93 ACPI_PARSE_OBJECT *Op,
98 AcpiDmInspectPossibleArgs (
99 UINT32 CurrentOpArgCount,
101 ACPI_PARSE_OBJECT *Op);
104 AcpiDmResourceDescendingOp (
105 ACPI_PARSE_OBJECT *Op,
110 /*******************************************************************************
112 * FUNCTION: AcpiDmDumpTree
114 * PARAMETERS: Origin - Starting object
118 * DESCRIPTION: Parse tree walk to format and output the nodes
120 ******************************************************************************/
124 ACPI_PARSE_OBJECT *Origin)
126 ACPI_OP_WALK_INFO Info;
134 AcpiOsPrintf ("/*\nAML Parse Tree\n\n");
138 Info.WalkState = NULL;
139 AcpiDmWalkParseTree (Origin, AcpiDmDumpDescending, NULL, &Info);
140 AcpiOsPrintf ("*/\n\n");
144 /*******************************************************************************
146 * FUNCTION: AcpiDmFindOrphanMethods
148 * PARAMETERS: Origin - Starting object
152 * DESCRIPTION: Parse tree walk to find "orphaned" method invocations -- methods
153 * that are not resolved in the namespace
155 ******************************************************************************/
158 AcpiDmFindOrphanMethods (
159 ACPI_PARSE_OBJECT *Origin)
161 ACPI_OP_WALK_INFO Info;
171 Info.WalkState = NULL;
172 AcpiDmWalkParseTree (Origin, AcpiDmFindOrphanDescending, NULL, &Info);
176 /*******************************************************************************
178 * FUNCTION: AcpiDmFinishNamespaceLoad
180 * PARAMETERS: ParseTreeRoot - Root of the parse tree
181 * NamespaceRoot - Root of the internal namespace
182 * OwnerId - OwnerId of the table to be disassembled
186 * DESCRIPTION: Load all namespace items that are created within control
187 * methods. Used before namespace cross reference
189 ******************************************************************************/
192 AcpiDmFinishNamespaceLoad (
193 ACPI_PARSE_OBJECT *ParseTreeRoot,
194 ACPI_NAMESPACE_NODE *NamespaceRoot,
195 ACPI_OWNER_ID OwnerId)
198 ACPI_OP_WALK_INFO Info;
199 ACPI_WALK_STATE *WalkState;
207 /* Create and initialize a new walk state */
209 WalkState = AcpiDsCreateWalkState (OwnerId, ParseTreeRoot, NULL, NULL);
215 Status = AcpiDsScopeStackPush (NamespaceRoot, NamespaceRoot->Type, WalkState);
216 if (ACPI_FAILURE (Status))
223 Info.WalkState = WalkState;
224 AcpiDmWalkParseTree (ParseTreeRoot, AcpiDmLoadDescendingOp,
225 AcpiDmCommonAscendingOp, &Info);
226 ACPI_FREE (WalkState);
230 /*******************************************************************************
232 * FUNCTION: AcpiDmCrossReferenceNamespace
234 * PARAMETERS: ParseTreeRoot - Root of the parse tree
235 * NamespaceRoot - Root of the internal namespace
236 * OwnerId - OwnerId of the table to be disassembled
240 * DESCRIPTION: Cross reference the namespace to create externals
242 ******************************************************************************/
245 AcpiDmCrossReferenceNamespace (
246 ACPI_PARSE_OBJECT *ParseTreeRoot,
247 ACPI_NAMESPACE_NODE *NamespaceRoot,
248 ACPI_OWNER_ID OwnerId)
251 ACPI_OP_WALK_INFO Info;
252 ACPI_WALK_STATE *WalkState;
260 /* Create and initialize a new walk state */
262 WalkState = AcpiDsCreateWalkState (OwnerId, ParseTreeRoot, NULL, NULL);
268 Status = AcpiDsScopeStackPush (NamespaceRoot, NamespaceRoot->Type, WalkState);
269 if (ACPI_FAILURE (Status))
276 Info.WalkState = WalkState;
277 AcpiDmWalkParseTree (ParseTreeRoot, AcpiDmXrefDescendingOp,
278 AcpiDmCommonAscendingOp, &Info);
279 ACPI_FREE (WalkState);
283 /*******************************************************************************
285 * FUNCTION: AcpiDmConvertResourceIndexes
287 * PARAMETERS: ParseTreeRoot - Root of the parse tree
288 * NamespaceRoot - Root of the internal namespace
292 * DESCRIPTION: Convert fixed-offset references to resource descriptors to
293 * symbolic references. Should only be called after namespace has
294 * been cross referenced.
296 ******************************************************************************/
299 AcpiDmConvertResourceIndexes (
300 ACPI_PARSE_OBJECT *ParseTreeRoot,
301 ACPI_NAMESPACE_NODE *NamespaceRoot)
304 ACPI_OP_WALK_INFO Info;
305 ACPI_WALK_STATE *WalkState;
313 /* Create and initialize a new walk state */
315 WalkState = AcpiDsCreateWalkState (0, ParseTreeRoot, NULL, NULL);
321 Status = AcpiDsScopeStackPush (NamespaceRoot, NamespaceRoot->Type, WalkState);
322 if (ACPI_FAILURE (Status))
329 Info.WalkState = WalkState;
330 AcpiDmWalkParseTree (ParseTreeRoot, AcpiDmResourceDescendingOp,
331 AcpiDmCommonAscendingOp, &Info);
332 ACPI_FREE (WalkState);
337 /*******************************************************************************
339 * FUNCTION: AcpiDmDumpDescending
341 * PARAMETERS: ASL_WALK_CALLBACK
345 * DESCRIPTION: Format and print contents of one parse Op.
347 ******************************************************************************/
350 AcpiDmDumpDescending (
351 ACPI_PARSE_OBJECT *Op,
355 ACPI_OP_WALK_INFO *Info = Context;
364 /* Most of the information (count, level, name) here */
367 AcpiOsPrintf ("% 5d [%2.2d] ", Info->Count, Level);
368 AcpiDmIndent (Level);
369 AcpiOsPrintf ("%-28s", AcpiPsGetOpcodeName (Op->Common.AmlOpcode));
371 /* Extra info is helpful */
373 switch (Op->Common.AmlOpcode)
378 AcpiOsPrintf ("%X", (UINT32) Op->Common.Value.Integer);
381 case AML_INT_NAMEPATH_OP:
382 if (Op->Common.Value.String)
384 AcpiNsExternalizeName (ACPI_UINT32_MAX, Op->Common.Value.String,
386 AcpiOsPrintf ("%s %p", Path, Op->Common.Node);
391 AcpiOsPrintf ("[NULL]");
398 case AML_INT_NAMEDFIELD_OP:
399 AcpiOsPrintf ("%4.4s", ACPI_CAST_PTR (char, &Op->Named.Name));
411 /*******************************************************************************
413 * FUNCTION: AcpiDmFindOrphanDescending
415 * PARAMETERS: ASL_WALK_CALLBACK
419 * DESCRIPTION: Check namepath Ops for orphaned method invocations
421 * Note: Experimental.
423 ******************************************************************************/
426 AcpiDmFindOrphanDescending (
427 ACPI_PARSE_OBJECT *Op,
431 const ACPI_OPCODE_INFO *OpInfo;
432 ACPI_PARSE_OBJECT *ChildOp;
433 ACPI_PARSE_OBJECT *NextOp;
434 ACPI_PARSE_OBJECT *ParentOp;
443 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
445 switch (Op->Common.AmlOpcode)
447 #ifdef ACPI_UNDER_DEVELOPMENT
449 ChildOp = Op->Common.Value.Arg;
450 if ((ChildOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
451 !ChildOp->Common.Node)
453 AcpiNsExternalizeName (ACPI_UINT32_MAX, ChildOp->Common.Value.String,
455 AcpiOsPrintf ("/* %-16s A-NAMEPATH: %s */\n", Op->Common.AmlOpName, Path);
458 NextOp = Op->Common.Next;
461 /* This NamePath has no args, assume it is an integer */
463 AcpiDmAddToExternalList (ChildOp, ChildOp->Common.Value.String, ACPI_TYPE_INTEGER, 0);
467 ArgCount = AcpiDmInspectPossibleArgs (3, 1, NextOp);
468 AcpiOsPrintf ("/* A-CHILDREN: %u Actual %u */\n", ArgCount, AcpiDmCountChildren (Op));
472 /* One Arg means this is just a Store(Name,Target) */
474 AcpiDmAddToExternalList (ChildOp, ChildOp->Common.Value.String, ACPI_TYPE_INTEGER, 0);
478 AcpiDmAddToExternalList (ChildOp, ChildOp->Common.Value.String, ACPI_TYPE_METHOD, ArgCount);
485 ChildOp = Op->Common.Value.Arg;
486 if ((ChildOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
487 !ChildOp->Common.Node)
489 NextOp = Op->Common.Next;
492 /* This NamePath has no args, assume it is an integer */
494 AcpiDmAddToExternalList (ChildOp, ChildOp->Common.Value.String, ACPI_TYPE_INTEGER, 0);
498 ArgCount = AcpiDmInspectPossibleArgs (2, 1, NextOp);
501 /* One Arg means this is just a Store(Name,Target) */
503 AcpiDmAddToExternalList (ChildOp, ChildOp->Common.Value.String, ACPI_TYPE_INTEGER, 0);
507 AcpiDmAddToExternalList (ChildOp, ChildOp->Common.Value.String, ACPI_TYPE_METHOD, ArgCount);
511 case AML_INT_NAMEPATH_OP:
513 /* Must examine parent to see if this namepath is an argument */
515 ParentOp = Op->Common.Parent;
516 OpInfo = AcpiPsGetOpcodeInfo (ParentOp->Common.AmlOpcode);
518 if ((OpInfo->Class != AML_CLASS_EXECUTE) &&
519 (OpInfo->Class != AML_CLASS_CREATE) &&
520 (ParentOp->Common.AmlOpcode != AML_INT_METHODCALL_OP) &&
523 ArgCount = AcpiDmInspectPossibleArgs (0, 0, Op->Common.Next);
526 * Check if namepath is a predicate for if/while or lone parameter to
531 if (((ParentOp->Common.AmlOpcode == AML_IF_OP) ||
532 (ParentOp->Common.AmlOpcode == AML_WHILE_OP) ||
533 (ParentOp->Common.AmlOpcode == AML_RETURN_OP)) &&
535 /* And namepath is the first argument */
536 (ParentOp->Common.Value.Arg == Op))
538 AcpiDmAddToExternalList (Op, Op->Common.Value.String, ACPI_TYPE_INTEGER, 0);
544 * This is a standalone namestring (not a parameter to another
545 * operator) - it *must* be a method invocation, nothing else is
546 * grammatically possible.
548 AcpiDmAddToExternalList (Op, Op->Common.Value.String, ACPI_TYPE_METHOD, ArgCount);
561 /*******************************************************************************
563 * FUNCTION: AcpiDmLoadDescendingOp
565 * PARAMETERS: ASL_WALK_CALLBACK
569 * DESCRIPTION: Descending handler for namespace control method object load
571 ******************************************************************************/
574 AcpiDmLoadDescendingOp (
575 ACPI_PARSE_OBJECT *Op,
579 ACPI_OP_WALK_INFO *Info = Context;
580 const ACPI_OPCODE_INFO *OpInfo;
581 ACPI_WALK_STATE *WalkState;
582 ACPI_OBJECT_TYPE ObjectType;
585 ACPI_PARSE_OBJECT *NextOp;
586 ACPI_NAMESPACE_NODE *Node;
588 BOOLEAN PreDefined = FALSE;
589 UINT8 PreDefineIndex = 0;
592 WalkState = Info->WalkState;
593 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
594 ObjectType = OpInfo->ObjectType;
595 ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode);
597 /* Only interested in operators that create new names */
599 if (!(OpInfo->Flags & AML_NAMED) &&
600 !(OpInfo->Flags & AML_CREATE))
605 /* Get the NamePath from the appropriate place */
607 if (OpInfo->Flags & AML_NAMED)
609 /* For all named operators, get the new name */
611 Path = (char *) Op->Named.Path;
613 if (!Path && Op->Common.AmlOpcode == AML_INT_NAMEDFIELD_OP)
615 *ACPI_CAST_PTR (UINT32, &FieldPath[0]) = Op->Named.Name;
620 else if (OpInfo->Flags & AML_CREATE)
622 /* New name is the last child */
624 NextOp = Op->Common.Value.Arg;
626 while (NextOp->Common.Next)
628 NextOp = NextOp->Common.Next;
630 Path = NextOp->Common.Value.String;
638 /* Insert the name into the namespace */
640 Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ObjectType,
641 ACPI_IMODE_LOAD_PASS2, ACPI_NS_DONT_OPEN_SCOPE,
644 Op->Common.Node = Node;
646 if (ACPI_SUCCESS (Status))
648 /* Check if it's a predefined node */
650 while (AcpiGbl_PreDefinedNames[PreDefineIndex].Name)
652 if (!ACPI_STRNCMP (Node->Name.Ascii,
653 AcpiGbl_PreDefinedNames[PreDefineIndex].Name, 4))
663 * Set node owner id if it satisfies all the following conditions:
664 * 1) Not a predefined node, _SB_ etc
665 * 2) Not the root node
666 * 3) Not a node created by Scope
669 if (!PreDefined && Node != AcpiGbl_RootNode &&
670 Op->Common.AmlOpcode != AML_SCOPE_OP)
672 Node->OwnerId = WalkState->OwnerId;
679 if (AcpiNsOpensScope (ObjectType))
683 Status = AcpiDsScopeStackPush (Op->Common.Node, ObjectType, WalkState);
684 if (ACPI_FAILURE (Status))
695 /*******************************************************************************
697 * FUNCTION: AcpiDmXrefDescendingOp
699 * PARAMETERS: ASL_WALK_CALLBACK
703 * DESCRIPTION: Descending handler for namespace cross reference
705 ******************************************************************************/
708 AcpiDmXrefDescendingOp (
709 ACPI_PARSE_OBJECT *Op,
713 ACPI_OP_WALK_INFO *Info = Context;
714 const ACPI_OPCODE_INFO *OpInfo;
715 ACPI_WALK_STATE *WalkState;
716 ACPI_OBJECT_TYPE ObjectType;
717 ACPI_OBJECT_TYPE ObjectType2;
720 ACPI_PARSE_OBJECT *NextOp;
721 ACPI_NAMESPACE_NODE *Node;
722 ACPI_OPERAND_OBJECT *Object;
723 UINT32 ParamCount = 0;
726 WalkState = Info->WalkState;
727 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
728 ObjectType = OpInfo->ObjectType;
729 ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode);
731 if ((!(OpInfo->Flags & AML_NAMED)) &&
732 (!(OpInfo->Flags & AML_CREATE)) &&
733 (Op->Common.AmlOpcode != AML_INT_NAMEPATH_OP))
738 /* Get the NamePath from the appropriate place */
740 if (OpInfo->Flags & AML_NAMED)
742 if ((Op->Common.AmlOpcode == AML_ALIAS_OP) ||
743 (Op->Common.AmlOpcode == AML_SCOPE_OP))
746 * Only these two operators refer to an existing name,
749 Path = (char *) Op->Named.Path;
752 else if (OpInfo->Flags & AML_CREATE)
754 /* Referenced Buffer Name is the first child */
756 NextOp = Op->Common.Value.Arg;
757 if (NextOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP)
759 Path = NextOp->Common.Value.String;
764 Path = Op->Common.Value.String;
773 * Lookup the name in the namespace. Name must exist at this point, or it
774 * is an invalid reference.
776 * The namespace is also used as a lookup table for references to resource
777 * descriptors and the fields within them.
779 Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ACPI_TYPE_ANY,
780 ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
782 if (ACPI_FAILURE (Status))
784 if (Status == AE_NOT_FOUND)
786 AcpiDmAddToExternalList (Op, Path, (UINT8) ObjectType, 0);
789 * We could install this into the namespace, but we catch duplicate
790 * externals when they are added to the list.
793 Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ACPI_TYPE_ANY,
794 ACPI_IMODE_LOAD_PASS1, ACPI_NS_DONT_OPEN_SCOPE,
801 * Found the node in external table, add it to external list
802 * Node->OwnerId == 0 indicates built-in ACPI Names, _OS_ etc
804 else if (Node->OwnerId && WalkState->OwnerId != Node->OwnerId)
806 ObjectType2 = ObjectType;
808 Object = AcpiNsGetAttachedObject (Node);
811 ObjectType2 = Object->Common.Type;
812 if (ObjectType2 == ACPI_TYPE_METHOD)
814 ParamCount = Object->Method.ParamCount;
818 AcpiDmAddToExternalList (Op, Path, (UINT8) ObjectType2, ParamCount);
819 Op->Common.Node = Node;
823 Op->Common.Node = Node;
828 /* Open new scope if necessary */
830 if (AcpiNsOpensScope (ObjectType))
834 Status = AcpiDsScopeStackPush (Op->Common.Node, ObjectType, WalkState);
835 if (ACPI_FAILURE (Status))
846 /*******************************************************************************
848 * FUNCTION: AcpiDmResourceDescendingOp
850 * PARAMETERS: ASL_WALK_CALLBACK
854 * DESCRIPTION: Process one parse op during symbolic resource index conversion.
856 ******************************************************************************/
859 AcpiDmResourceDescendingOp (
860 ACPI_PARSE_OBJECT *Op,
864 ACPI_OP_WALK_INFO *Info = Context;
865 const ACPI_OPCODE_INFO *OpInfo;
866 ACPI_WALK_STATE *WalkState;
867 ACPI_OBJECT_TYPE ObjectType;
871 WalkState = Info->WalkState;
872 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
874 /* Open new scope if necessary */
876 ObjectType = OpInfo->ObjectType;
877 if (AcpiNsOpensScope (ObjectType))
882 Status = AcpiDsScopeStackPush (Op->Common.Node, ObjectType, WalkState);
883 if (ACPI_FAILURE (Status))
891 * Check if this operator contains a reference to a resource descriptor.
892 * If so, convert the reference into a symbolic reference.
894 AcpiDmCheckResourceReference (Op, WalkState);
899 /*******************************************************************************
901 * FUNCTION: AcpiDmCommonAscendingOp
903 * PARAMETERS: ASL_WALK_CALLBACK
907 * DESCRIPTION: Ascending handler for combined parse/namespace walks. Closes
908 * scope if necessary.
910 ******************************************************************************/
913 AcpiDmCommonAscendingOp (
914 ACPI_PARSE_OBJECT *Op,
918 ACPI_OP_WALK_INFO *Info = Context;
919 const ACPI_OPCODE_INFO *OpInfo;
920 ACPI_OBJECT_TYPE ObjectType;
923 /* Close scope if necessary */
925 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
926 ObjectType = OpInfo->ObjectType;
927 ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode);
929 if (AcpiNsOpensScope (ObjectType))
931 (void) AcpiDsScopeStackPop (Info->WalkState);
938 /*******************************************************************************
940 * FUNCTION: AcpiDmInspectPossibleArgs
942 * PARAMETERS: CurrentOpArgCount - Which arg of the current op was the
943 * possible method invocation found
944 * TargetCount - Number of targets (0,1,2) for this op
949 * DESCRIPTION: Examine following args and next ops for possible arguments
950 * for an unrecognized method invocation.
952 ******************************************************************************/
955 AcpiDmInspectPossibleArgs (
956 UINT32 CurrentOpArgCount,
958 ACPI_PARSE_OBJECT *Op)
960 const ACPI_OPCODE_INFO *OpInfo;
966 Lookahead = (ACPI_METHOD_NUM_ARGS + TargetCount) - CurrentOpArgCount;
968 /* Lookahead for the maximum number of possible arguments */
970 for (i = 0; i < Lookahead; i++)
977 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
980 * Any one of these operators is "very probably" not a method arg
982 if ((Op->Common.AmlOpcode == AML_STORE_OP) ||
983 (Op->Common.AmlOpcode == AML_NOTIFY_OP))
988 if ((OpInfo->Class != AML_CLASS_EXECUTE) &&
989 (OpInfo->Class != AML_CLASS_CONTROL))
994 Op = Op->Common.Next;