1 /*******************************************************************************
3 * Module Name: dmcstyle - Support for C-style operator disassembly
5 ******************************************************************************/
8 * Copyright (C) 2000 - 2016, 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.
50 #ifdef ACPI_DISASSEMBLER
52 #define _COMPONENT ACPI_CA_DEBUGGER
53 ACPI_MODULE_NAME ("dmcstyle")
56 /* Local prototypes */
59 AcpiDmGetCompoundSymbol (
64 ACPI_PARSE_OBJECT *Op,
65 ACPI_PARSE_OBJECT *Target);
69 ACPI_PARSE_OBJECT *Op);
72 AcpiDmIsTargetAnOperand (
73 ACPI_PARSE_OBJECT *Target,
74 ACPI_PARSE_OBJECT *Operand,
78 /*******************************************************************************
80 * FUNCTION: AcpiDmCheckForSymbolicOpcode
82 * PARAMETERS: Op - Current parse object
83 * Walk - Current parse tree walk info
85 * RETURN: TRUE if opcode can be converted to symbolic, FALSE otherwise
87 * DESCRIPTION: This is the main code that implements disassembly of AML code
88 * to C-style operators. Called during descending phase of the
91 ******************************************************************************/
94 AcpiDmCheckForSymbolicOpcode (
95 ACPI_PARSE_OBJECT *Op,
96 ACPI_OP_WALK_INFO *Info)
98 char *OperatorSymbol = NULL;
99 ACPI_PARSE_OBJECT *Child1;
100 ACPI_PARSE_OBJECT *Child2;
101 ACPI_PARSE_OBJECT *Target;
102 ACPI_PARSE_OBJECT *GrandChild1;
103 ACPI_PARSE_OBJECT *GrandChild2;
104 ACPI_PARSE_OBJECT *GrandTarget = NULL;
107 /* Exit immediately if ASL+ not enabled */
109 if (!AcpiGbl_CstyleDisassembly)
114 /* Check for a non-ASL+ statement, propagate the flag */
116 if (Op->Common.Parent->Common.DisasmFlags & ACPI_PARSEOP_LEGACY_ASL_ONLY)
118 Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
122 /* Get the first operand */
124 Child1 = AcpiPsGetArg (Op, 0);
130 /* Get the second operand */
132 Child2 = Child1->Common.Next;
134 /* Setup the operator string for this opcode */
136 switch (Op->Common.AmlOpcode)
139 OperatorSymbol = " + ";
142 case AML_SUBTRACT_OP:
143 OperatorSymbol = " - ";
146 case AML_MULTIPLY_OP:
147 OperatorSymbol = " * ";
151 OperatorSymbol = " / ";
155 OperatorSymbol = " % ";
158 case AML_SHIFT_LEFT_OP:
159 OperatorSymbol = " << ";
162 case AML_SHIFT_RIGHT_OP:
163 OperatorSymbol = " >> ";
167 OperatorSymbol = " & ";
171 OperatorSymbol = " | ";
175 OperatorSymbol = " ^ ";
178 /* Logical operators, no target */
181 OperatorSymbol = " && ";
185 OperatorSymbol = " == ";
188 case AML_LGREATER_OP:
189 OperatorSymbol = " > ";
193 OperatorSymbol = " < ";
197 OperatorSymbol = " || ";
202 * Check for the LNOT sub-opcodes. These correspond to
203 * LNotEqual, LLessEqual, and LGreaterEqual. There are
204 * no actual AML opcodes for these operators.
206 switch (Child1->Common.AmlOpcode)
209 OperatorSymbol = " != ";
212 case AML_LGREATER_OP:
213 OperatorSymbol = " <= ";
217 OperatorSymbol = " >= ";
222 /* Unary LNOT case, emit "!" immediately */
228 Child1->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX;
229 Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX;
230 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
232 /* Save symbol string in the next child (not peer) */
234 Child2 = AcpiPsGetArg (Child1, 0);
240 Child2->Common.OperatorSymbol = OperatorSymbol;
245 * Check for constant source operand. Note: although technically
246 * legal syntax, the iASL compiler does not support this with
247 * the symbolic operators for Index(). It doesn't make sense to
248 * use Index() with a constant anyway.
250 if ((Child1->Common.AmlOpcode == AML_STRING_OP) ||
251 (Child1->Common.AmlOpcode == AML_BUFFER_OP) ||
252 (Child1->Common.AmlOpcode == AML_PACKAGE_OP) ||
253 (Child1->Common.AmlOpcode == AML_VAR_PACKAGE_OP))
255 Op->Common.DisasmFlags |= ACPI_PARSEOP_CLOSING_PAREN;
259 /* Index operator is [] */
261 Child1->Common.OperatorSymbol = " [";
262 Child2->Common.OperatorSymbol = "]";
265 /* Unary operators */
267 case AML_DECREMENT_OP:
268 OperatorSymbol = "--";
271 case AML_INCREMENT_OP:
272 OperatorSymbol = "++";
277 OperatorSymbol = NULL;
284 if (Child1->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX)
290 * This is the key to how the disassembly of the C-style operators
291 * works. We save the operator symbol in the first child, thus
292 * deferring symbol output until after the first operand has been
295 if (!Child1->Common.OperatorSymbol)
297 Child1->Common.OperatorSymbol = OperatorSymbol;
301 * Check for a valid target as the 3rd (or sometimes 2nd) operand
303 * Compound assignment operator support:
304 * Attempt to optimize constructs of the form:
305 * Add (Local1, 0xFF, Local1)
309 * Only the math operators and Store() have a target.
310 * Logicals have no target.
312 switch (Op->Common.AmlOpcode)
315 case AML_SUBTRACT_OP:
316 case AML_MULTIPLY_OP:
319 case AML_SHIFT_LEFT_OP:
320 case AML_SHIFT_RIGHT_OP:
325 /* Target is 3rd operand */
327 Target = Child2->Common.Next;
328 if (Op->Common.AmlOpcode == AML_DIVIDE_OP)
331 * Divide has an extra target operand (Remainder).
332 * If this extra target is specified, it cannot be converted
333 * to a C-style operator
335 if (AcpiDmIsValidTarget (Target))
337 Child1->Common.OperatorSymbol = NULL;
338 Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
342 Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
343 Target = Target->Common.Next;
346 /* Parser should ensure there is at least a placeholder target */
353 if (!AcpiDmIsValidTarget (Target))
355 if (Op->Common.Parent->Common.AmlOpcode == AML_STORE_OP)
357 Op->Common.DisasmFlags = 0;
358 Child1->Common.OperatorSymbol = NULL;
362 /* Not a valid target (placeholder only, from parser) */
367 * Promote the target up to the first child in the parse
368 * tree. This is done because the target will be output
369 * first, in the form:
370 * <Target> = Operands...
372 AcpiDmPromoteTarget (Op, Target);
374 /* Check operands for conversion to a "Compound Assignment" */
376 switch (Op->Common.AmlOpcode)
378 /* Commutative operators */
381 case AML_MULTIPLY_OP:
386 * For the commutative operators, we can convert to a
387 * compound statement only if at least one (either) operand
388 * is the same as the target.
390 * Add (A, B, A) --> A += B
391 * Add (B, A, A) --> A += B
392 * Add (B, C, A) --> A = (B + C)
394 if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE)) ||
395 (AcpiDmIsTargetAnOperand (Target, Child2, TRUE)))
397 Target->Common.OperatorSymbol =
398 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
400 /* Convert operator to compound assignment */
402 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
403 Child1->Common.OperatorSymbol = NULL;
408 /* Non-commutative operators */
410 case AML_SUBTRACT_OP:
413 case AML_SHIFT_LEFT_OP:
414 case AML_SHIFT_RIGHT_OP:
416 * For the non-commutative operators, we can convert to a
417 * compound statement only if the target is the same as the
420 * Subtract (A, B, A) --> A -= B
421 * Subtract (B, A, A) --> A = (B - A)
423 if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE)))
425 Target->Common.OperatorSymbol =
426 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
428 /* Convert operator to compound assignment */
430 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
431 Child1->Common.OperatorSymbol = NULL;
441 * If we are within a C-style expression, emit an extra open
442 * paren. Implemented by examining the parent op.
444 switch (Op->Common.Parent->Common.AmlOpcode)
447 case AML_SUBTRACT_OP:
448 case AML_MULTIPLY_OP:
451 case AML_SHIFT_LEFT_OP:
452 case AML_SHIFT_RIGHT_OP:
458 case AML_LGREATER_OP:
462 Op->Common.DisasmFlags |= ACPI_PARSEOP_ASSIGNMENT;
470 /* Normal output for ASL/AML operators with a target operand */
472 Target->Common.OperatorSymbol = " = (";
475 /* Binary operators, no parens */
477 case AML_DECREMENT_OP:
478 case AML_INCREMENT_OP:
483 /* Target is optional, 3rd operand */
485 Target = Child2->Common.Next;
486 if (AcpiDmIsValidTarget (Target))
488 AcpiDmPromoteTarget (Op, Target);
490 if (!Target->Common.OperatorSymbol)
492 Target->Common.OperatorSymbol = " = ";
499 * Target is the 2nd operand.
500 * We know the target is valid, it is not optional.
502 * The following block implements "Ignore conversion if a store
503 * is followed by a math/bit operator that has no target". Used
504 * only for the ASL test suite.
506 if (!AcpiGbl_DoDisassemblerOptimizations)
508 switch (Child1->Common.AmlOpcode)
510 /* This operator has two operands and two targets */
514 GrandChild1 = Child1->Common.Value.Arg;
515 GrandChild2 = GrandChild1->Common.Next;
516 GrandTarget = GrandChild2->Common.Next;
518 if (GrandTarget && !AcpiDmIsValidTarget (GrandTarget))
520 Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
523 GrandTarget = GrandTarget->Common.Next;
527 case AML_SUBTRACT_OP:
528 case AML_MULTIPLY_OP:
530 case AML_SHIFT_LEFT_OP:
531 case AML_SHIFT_RIGHT_OP:
537 /* These operators have two operands and a target */
539 GrandChild1 = Child1->Common.Value.Arg;
540 GrandChild2 = GrandChild1->Common.Next;
541 GrandTarget = GrandChild2->Common.Next;
546 /* This operator has one operand and a target */
548 GrandChild1 = Child1->Common.Value.Arg;
549 GrandTarget = GrandChild1->Common.Next;
556 if (GrandTarget && !AcpiDmIsValidTarget (GrandTarget))
558 Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY;
564 * In the parse tree, simply swap the target with the
565 * source so that the target is processed first.
567 Target = Child1->Common.Next;
573 AcpiDmPromoteTarget (Op, Target);
574 if (!Target->Common.OperatorSymbol)
576 Target->Common.OperatorSymbol = " = ";
582 /* Target is optional, 2nd operand */
584 Target = Child1->Common.Next;
590 if (AcpiDmIsValidTarget (Target))
592 /* Valid target, not a placeholder */
594 AcpiDmPromoteTarget (Op, Target);
595 Target->Common.OperatorSymbol = " = ~";
599 /* No target. Emit this prefix operator immediately */
610 * Nodes marked with ACPI_PARSEOP_PARAMLIST don't need a parens
611 * output here. We also need to check the parent to see if this op
612 * is part of a compound test (!=, >=, <=).
614 if ((Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) ||
615 ((Op->Common.Parent->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) &&
616 (Op->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX)))
618 /* Do Nothing. Paren already generated */
622 /* All other operators, emit an open paren */
629 /*******************************************************************************
631 * FUNCTION: AcpiDmCloseOperator
633 * PARAMETERS: Op - Current parse object
637 * DESCRIPTION: Closes an operator by adding a closing parentheses if and
638 * when necessary. Called during ascending phase of the
641 ******************************************************************************/
644 AcpiDmCloseOperator (
645 ACPI_PARSE_OBJECT *Op)
647 BOOLEAN IsCStyleOp = FALSE;
650 /* Always emit paren if ASL+ disassembly disabled */
652 if (!AcpiGbl_CstyleDisassembly)
658 /* Check for a non-ASL+ statement */
660 if (Op->Common.DisasmFlags & ACPI_PARSEOP_LEGACY_ASL_ONLY)
666 /* Check if we need to add an additional closing paren */
668 switch (Op->Common.AmlOpcode)
671 case AML_SUBTRACT_OP:
672 case AML_MULTIPLY_OP:
675 case AML_SHIFT_LEFT_OP:
676 case AML_SHIFT_RIGHT_OP:
682 case AML_LGREATER_OP:
686 /* Emit paren only if this is not a compound assignment */
688 if (Op->Common.DisasmFlags & ACPI_PARSEOP_COMPOUND_ASSIGNMENT)
693 /* Emit extra close paren for assignment within an expression */
695 if (Op->Common.DisasmFlags & ACPI_PARSEOP_ASSIGNMENT)
705 /* This is case for unsupported Index() source constants */
707 if (Op->Common.DisasmFlags & ACPI_PARSEOP_CLOSING_PAREN)
713 /* No need for parens for these */
715 case AML_DECREMENT_OP:
716 case AML_INCREMENT_OP:
724 /* Always emit paren for non-ASL+ operators */
729 * Nodes marked with ACPI_PARSEOP_PARAMLIST don't need a parens
730 * output here. We also need to check the parent to see if this op
731 * is part of a compound test (!=, >=, <=).
734 ((Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) ||
735 ((Op->Common.Parent->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) &&
736 (Op->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX))))
746 /*******************************************************************************
748 * FUNCTION: AcpiDmGetCompoundSymbol
750 * PARAMETERS: AslOpcode
752 * RETURN: String containing the compound assignment symbol
754 * DESCRIPTION: Detect opcodes that can be converted to compound assignment,
755 * return the appropriate operator string.
757 ******************************************************************************/
760 AcpiDmGetCompoundSymbol (
772 case AML_SUBTRACT_OP:
776 case AML_MULTIPLY_OP:
788 case AML_SHIFT_LEFT_OP:
792 case AML_SHIFT_RIGHT_OP:
810 /* No operator string for all other opcodes */
819 /*******************************************************************************
821 * FUNCTION: AcpiDmPromoteTarget
823 * PARAMETERS: Op - Operator parse object
824 * Target - Target associate with the Op
828 * DESCRIPTION: Transform the parse tree by moving the target up to the first
831 ******************************************************************************/
834 AcpiDmPromoteTarget (
835 ACPI_PARSE_OBJECT *Op,
836 ACPI_PARSE_OBJECT *Target)
838 ACPI_PARSE_OBJECT *Child;
841 /* Link target directly to the Op as first child */
843 Child = Op->Common.Value.Arg;
844 Op->Common.Value.Arg = Target;
845 Target->Common.Next = Child;
847 /* Find the last peer, it is linked to the target. Unlink it. */
849 while (Child->Common.Next != Target)
851 Child = Child->Common.Next;
854 Child->Common.Next = NULL;
858 /*******************************************************************************
860 * FUNCTION: AcpiDmIsValidTarget
862 * PARAMETERS: Target - Target Op from the parse tree
864 * RETURN: TRUE if the Target is real. FALSE if it is just a placeholder
865 * Op that was inserted by the parser.
867 * DESCRIPTION: Determine if a Target Op is a placeholder Op or a real Target.
868 * In other words, determine if the optional target is used or
869 * not. Note: If Target is NULL, something is seriously wrong,
870 * probably with the parse tree.
872 ******************************************************************************/
875 AcpiDmIsValidTarget (
876 ACPI_PARSE_OBJECT *Target)
884 if ((Target->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
885 (Target->Common.Value.Arg == NULL))
894 /*******************************************************************************
896 * FUNCTION: AcpiDmIsTargetAnOperand
898 * PARAMETERS: Target - Target associated with the expression
899 * Operand - An operand associated with expression
901 * RETURN: TRUE if expression can be converted to a compound assignment.
904 * DESCRIPTION: Determine if the Target duplicates the operand, in order to
905 * detect if the expression can be converted to a compound
906 * assigment. (+=, *=, etc.)
908 ******************************************************************************/
911 AcpiDmIsTargetAnOperand (
912 ACPI_PARSE_OBJECT *Target,
913 ACPI_PARSE_OBJECT *Operand,
916 const ACPI_OPCODE_INFO *OpInfo;
921 * Opcodes must match. Note: ignoring the difference between nameseg
922 * and namepath for now. May be needed later.
924 if (Target->Common.AmlOpcode != Operand->Common.AmlOpcode)
929 /* Nodes should match, even if they are NULL */
931 if (Target->Common.Node != Operand->Common.Node)
936 /* Determine if a child exists */
938 OpInfo = AcpiPsGetOpcodeInfo (Operand->Common.AmlOpcode);
939 if (OpInfo->Flags & AML_HAS_ARGS)
941 Same = AcpiDmIsTargetAnOperand (Target->Common.Value.Arg,
942 Operand->Common.Value.Arg, FALSE);
949 /* Check the next peer, as long as we are not at the top level */
954 Same = AcpiDmIsTargetAnOperand (Target->Common.Next,
955 Operand->Common.Next, FALSE);
962 /* Supress the duplicate operand at the top-level */
966 Operand->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;