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;
104 /* Exit immediately if ASL+ not enabled */
106 if (!AcpiGbl_CstyleDisassembly)
111 /* Get the first operand */
113 Child1 = AcpiPsGetArg (Op, 0);
119 /* Get the second operand */
121 Child2 = Child1->Common.Next;
123 /* Setup the operator string for this opcode */
125 switch (Op->Common.AmlOpcode)
128 OperatorSymbol = " + ";
131 case AML_SUBTRACT_OP:
132 OperatorSymbol = " - ";
135 case AML_MULTIPLY_OP:
136 OperatorSymbol = " * ";
140 OperatorSymbol = " / ";
144 OperatorSymbol = " % ";
147 case AML_SHIFT_LEFT_OP:
148 OperatorSymbol = " << ";
151 case AML_SHIFT_RIGHT_OP:
152 OperatorSymbol = " >> ";
156 OperatorSymbol = " & ";
160 OperatorSymbol = " | ";
164 OperatorSymbol = " ^ ";
167 /* Logical operators, no target */
170 OperatorSymbol = " && ";
174 OperatorSymbol = " == ";
177 case AML_LGREATER_OP:
178 OperatorSymbol = " > ";
182 OperatorSymbol = " < ";
186 OperatorSymbol = " || ";
191 * Check for the LNOT sub-opcodes. These correspond to
192 * LNotEqual, LLessEqual, and LGreaterEqual. There are
193 * no actual AML opcodes for these operators.
195 switch (Child1->Common.AmlOpcode)
198 OperatorSymbol = " != ";
201 case AML_LGREATER_OP:
202 OperatorSymbol = " <= ";
206 OperatorSymbol = " >= ";
211 /* Unary LNOT case, emit "!" immediately */
217 Child1->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX;
218 Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX;
219 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
221 /* Save symbol string in the next child (not peer) */
223 Child2 = AcpiPsGetArg (Child1, 0);
229 Child2->Common.OperatorSymbol = OperatorSymbol;
234 * Check for constant source operand. Note: although technically
235 * legal syntax, the iASL compiler does not support this with
236 * the symbolic operators for Index(). It doesn't make sense to
237 * use Index() with a constant anyway.
239 if ((Child1->Common.AmlOpcode == AML_STRING_OP) ||
240 (Child1->Common.AmlOpcode == AML_BUFFER_OP) ||
241 (Child1->Common.AmlOpcode == AML_PACKAGE_OP) ||
242 (Child1->Common.AmlOpcode == AML_VAR_PACKAGE_OP))
244 Op->Common.DisasmFlags |= ACPI_PARSEOP_CLOSING_PAREN;
248 /* Index operator is [] */
250 Child1->Common.OperatorSymbol = " [";
251 Child2->Common.OperatorSymbol = "]";
254 /* Unary operators */
256 case AML_DECREMENT_OP:
257 OperatorSymbol = "--";
260 case AML_INCREMENT_OP:
261 OperatorSymbol = "++";
266 OperatorSymbol = NULL;
273 if (Child1->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX)
279 * This is the key to how the disassembly of the C-style operators
280 * works. We save the operator symbol in the first child, thus
281 * deferring symbol output until after the first operand has been
284 if (!Child1->Common.OperatorSymbol)
286 Child1->Common.OperatorSymbol = OperatorSymbol;
290 * Check for a valid target as the 3rd (or sometimes 2nd) operand
292 * Compound assignment operator support:
293 * Attempt to optimize constructs of the form:
294 * Add (Local1, 0xFF, Local1)
298 * Only the math operators and Store() have a target.
299 * Logicals have no target.
301 switch (Op->Common.AmlOpcode)
304 case AML_SUBTRACT_OP:
305 case AML_MULTIPLY_OP:
308 case AML_SHIFT_LEFT_OP:
309 case AML_SHIFT_RIGHT_OP:
314 /* Target is 3rd operand */
316 Target = Child2->Common.Next;
317 if (Op->Common.AmlOpcode == AML_DIVIDE_OP)
320 * Divide has an extra target operand (Remainder).
321 * If this extra target is specified, it cannot be converted
322 * to a C-style operator
324 if (AcpiDmIsValidTarget (Target))
326 Child1->Common.OperatorSymbol = NULL;
330 Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
331 Target = Target->Common.Next;
334 /* Parser should ensure there is at least a placeholder target */
341 if (!AcpiDmIsValidTarget (Target))
343 /* Not a valid target (placeholder only, from parser) */
348 * Promote the target up to the first child in the parse
349 * tree. This is done because the target will be output
350 * first, in the form:
351 * <Target> = Operands...
353 AcpiDmPromoteTarget (Op, Target);
355 /* Check operands for conversion to a "Compound Assignment" */
357 switch (Op->Common.AmlOpcode)
359 /* Commutative operators */
362 case AML_MULTIPLY_OP:
367 * For the commutative operators, we can convert to a
368 * compound statement only if at least one (either) operand
369 * is the same as the target.
371 * Add (A, B, A) --> A += B
372 * Add (B, A, A) --> A += B
373 * Add (B, C, A) --> A = (B + C)
375 if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE)) ||
376 (AcpiDmIsTargetAnOperand (Target, Child2, TRUE)))
378 Target->Common.OperatorSymbol =
379 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
381 /* Convert operator to compound assignment */
383 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
384 Child1->Common.OperatorSymbol = NULL;
389 /* Non-commutative operators */
391 case AML_SUBTRACT_OP:
394 case AML_SHIFT_LEFT_OP:
395 case AML_SHIFT_RIGHT_OP:
397 * For the non-commutative operators, we can convert to a
398 * compound statement only if the target is the same as the
401 * Subtract (A, B, A) --> A -= B
402 * Subtract (B, A, A) --> A = (B - A)
404 if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE)))
406 Target->Common.OperatorSymbol =
407 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
409 /* Convert operator to compound assignment */
411 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT;
412 Child1->Common.OperatorSymbol = NULL;
422 * If we are within a C-style expression, emit an extra open
423 * paren. Implemented by examining the parent op.
425 switch (Op->Common.Parent->Common.AmlOpcode)
428 case AML_SUBTRACT_OP:
429 case AML_MULTIPLY_OP:
432 case AML_SHIFT_LEFT_OP:
433 case AML_SHIFT_RIGHT_OP:
439 case AML_LGREATER_OP:
443 Op->Common.DisasmFlags |= ACPI_PARSEOP_ASSIGNMENT;
451 /* Normal output for ASL/AML operators with a target operand */
453 Target->Common.OperatorSymbol = " = (";
456 /* Binary operators, no parens */
458 case AML_DECREMENT_OP:
459 case AML_INCREMENT_OP:
464 /* Target is optional, 3rd operand */
466 Target = Child2->Common.Next;
467 if (AcpiDmIsValidTarget (Target))
469 AcpiDmPromoteTarget (Op, Target);
471 if (!Target->Common.OperatorSymbol)
473 Target->Common.OperatorSymbol = " = ";
480 * Target is the 2nd operand.
481 * We know the target is valid, it is not optional.
482 * In the parse tree, simply swap the target with the
483 * source so that the target is processed first.
485 Target = Child1->Common.Next;
491 AcpiDmPromoteTarget (Op, Target);
492 if (!Target->Common.OperatorSymbol)
494 Target->Common.OperatorSymbol = " = ";
500 /* Target is optional, 2nd operand */
502 Target = Child1->Common.Next;
508 if (AcpiDmIsValidTarget (Target))
510 /* Valid target, not a placeholder */
512 AcpiDmPromoteTarget (Op, Target);
513 Target->Common.OperatorSymbol = " = ~";
517 /* No target. Emit this prefix operator immediately */
528 * Nodes marked with ACPI_PARSEOP_PARAMLIST don't need a parens
529 * output here. We also need to check the parent to see if this op
530 * is part of a compound test (!=, >=, <=).
532 if ((Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) ||
533 ((Op->Common.Parent->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) &&
534 (Op->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX)))
536 /* Do Nothing. Paren already generated */
540 /* All other operators, emit an open paren */
547 /*******************************************************************************
549 * FUNCTION: AcpiDmCloseOperator
551 * PARAMETERS: Op - Current parse object
555 * DESCRIPTION: Closes an operator by adding a closing parentheses if and
556 * when necessary. Called during ascending phase of the
559 ******************************************************************************/
562 AcpiDmCloseOperator (
563 ACPI_PARSE_OBJECT *Op)
565 BOOLEAN IsCStyleOp = FALSE;
567 /* Always emit paren if ASL+ disassembly disabled */
569 if (!AcpiGbl_CstyleDisassembly)
575 /* Check if we need to add an additional closing paren */
577 switch (Op->Common.AmlOpcode)
580 case AML_SUBTRACT_OP:
581 case AML_MULTIPLY_OP:
584 case AML_SHIFT_LEFT_OP:
585 case AML_SHIFT_RIGHT_OP:
591 case AML_LGREATER_OP:
595 /* Emit paren only if this is not a compound assignment */
597 if (Op->Common.DisasmFlags & ACPI_PARSEOP_COMPOUND_ASSIGNMENT)
602 /* Emit extra close paren for assignment within an expression */
604 if (Op->Common.DisasmFlags & ACPI_PARSEOP_ASSIGNMENT)
614 /* This is case for unsupported Index() source constants */
616 if (Op->Common.DisasmFlags & ACPI_PARSEOP_CLOSING_PAREN)
622 /* No need for parens for these */
624 case AML_DECREMENT_OP:
625 case AML_INCREMENT_OP:
633 /* Always emit paren for non-ASL+ operators */
638 * Nodes marked with ACPI_PARSEOP_PARAMLIST don't need a parens
639 * output here. We also need to check the parent to see if this op
640 * is part of a compound test (!=, >=, <=).
643 ((Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) ||
644 ((Op->Common.Parent->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) &&
645 (Op->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX))))
655 /*******************************************************************************
657 * FUNCTION: AcpiDmGetCompoundSymbol
659 * PARAMETERS: AslOpcode
661 * RETURN: String containing the compound assignment symbol
663 * DESCRIPTION: Detect opcodes that can be converted to compound assignment,
664 * return the appropriate operator string.
666 ******************************************************************************/
669 AcpiDmGetCompoundSymbol (
681 case AML_SUBTRACT_OP:
685 case AML_MULTIPLY_OP:
697 case AML_SHIFT_LEFT_OP:
701 case AML_SHIFT_RIGHT_OP:
719 /* No operator string for all other opcodes */
728 /*******************************************************************************
730 * FUNCTION: AcpiDmPromoteTarget
732 * PARAMETERS: Op - Operator parse object
733 * Target - Target associate with the Op
737 * DESCRIPTION: Transform the parse tree by moving the target up to the first
740 ******************************************************************************/
743 AcpiDmPromoteTarget (
744 ACPI_PARSE_OBJECT *Op,
745 ACPI_PARSE_OBJECT *Target)
747 ACPI_PARSE_OBJECT *Child;
750 /* Link target directly to the Op as first child */
752 Child = Op->Common.Value.Arg;
753 Op->Common.Value.Arg = Target;
754 Target->Common.Next = Child;
756 /* Find the last peer, it is linked to the target. Unlink it. */
758 while (Child->Common.Next != Target)
760 Child = Child->Common.Next;
763 Child->Common.Next = NULL;
767 /*******************************************************************************
769 * FUNCTION: AcpiDmIsValidTarget
771 * PARAMETERS: Target - Target Op from the parse tree
773 * RETURN: TRUE if the Target is real. FALSE if it is just a placeholder
774 * Op that was inserted by the parser.
776 * DESCRIPTION: Determine if a Target Op is a placeholder Op or a real Target.
777 * In other words, determine if the optional target is used or
778 * not. Note: If Target is NULL, something is seriously wrong,
779 * probably with the parse tree.
781 ******************************************************************************/
784 AcpiDmIsValidTarget (
785 ACPI_PARSE_OBJECT *Target)
793 if ((Target->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
794 (Target->Common.Value.Arg == NULL))
803 /*******************************************************************************
805 * FUNCTION: AcpiDmIsTargetAnOperand
807 * PARAMETERS: Target - Target associated with the expression
808 * Operand - An operand associated with expression
810 * RETURN: TRUE if expression can be converted to a compound assignment.
813 * DESCRIPTION: Determine if the Target duplicates the operand, in order to
814 * detect if the expression can be converted to a compound
815 * assigment. (+=, *=, etc.)
817 ******************************************************************************/
820 AcpiDmIsTargetAnOperand (
821 ACPI_PARSE_OBJECT *Target,
822 ACPI_PARSE_OBJECT *Operand,
825 const ACPI_OPCODE_INFO *OpInfo;
830 * Opcodes must match. Note: ignoring the difference between nameseg
831 * and namepath for now. May be needed later.
833 if (Target->Common.AmlOpcode != Operand->Common.AmlOpcode)
838 /* Nodes should match, even if they are NULL */
840 if (Target->Common.Node != Operand->Common.Node)
845 /* Determine if a child exists */
847 OpInfo = AcpiPsGetOpcodeInfo (Operand->Common.AmlOpcode);
848 if (OpInfo->Flags & AML_HAS_ARGS)
850 Same = AcpiDmIsTargetAnOperand (Target->Common.Value.Arg,
851 Operand->Common.Value.Arg, FALSE);
858 /* Check the next peer, as long as we are not at the top level */
863 Same = AcpiDmIsTargetAnOperand (Target->Common.Next,
864 Operand->Common.Next, FALSE);
871 /* Supress the duplicate operand at the top-level */
875 Operand->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;