1 /*******************************************************************************
3 * Module Name: dmcstyle - Support for C-style operator disassembly
5 ******************************************************************************/
8 * Copyright (C) 2000 - 2015, 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;
220 /* Save symbol string in the next child (not peer) */
222 Child2 = AcpiPsGetArg (Child1, 0);
228 Child2->Common.OperatorSymbol = OperatorSymbol;
233 * Check for constant source operand. Note: although technically
234 * legal syntax, the iASL compiler does not support this with
235 * the symbolic operators for Index(). It doesn't make sense to
236 * use Index() with a constant anyway.
238 if ((Child1->Common.AmlOpcode == AML_STRING_OP) ||
239 (Child1->Common.AmlOpcode == AML_BUFFER_OP) ||
240 (Child1->Common.AmlOpcode == AML_PACKAGE_OP) ||
241 (Child1->Common.AmlOpcode == AML_VAR_PACKAGE_OP))
243 Op->Common.DisasmFlags |= ACPI_PARSEOP_CLOSING_PAREN;
247 /* Index operator is [] */
249 Child1->Common.OperatorSymbol = " [";
250 Child2->Common.OperatorSymbol = "]";
253 /* Unary operators */
255 case AML_DECREMENT_OP:
256 OperatorSymbol = "--";
259 case AML_INCREMENT_OP:
260 OperatorSymbol = "++";
265 OperatorSymbol = NULL;
272 if (Child1->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX)
278 * This is the key to how the disassembly of the C-style operators
279 * works. We save the operator symbol in the first child, thus
280 * deferring symbol output until after the first operand has been
283 if (!Child1->Common.OperatorSymbol)
285 Child1->Common.OperatorSymbol = OperatorSymbol;
289 * Check for a valid target as the 3rd (or sometimes 2nd) operand
291 * Compound assignment operator support:
292 * Attempt to optimize constructs of the form:
293 * Add (Local1, 0xFF, Local1)
297 * Only the math operators and Store() have a target.
298 * Logicals have no target.
300 switch (Op->Common.AmlOpcode)
303 case AML_SUBTRACT_OP:
304 case AML_MULTIPLY_OP:
307 case AML_SHIFT_LEFT_OP:
308 case AML_SHIFT_RIGHT_OP:
313 /* Target is 3rd operand */
315 Target = Child2->Common.Next;
316 if (Op->Common.AmlOpcode == AML_DIVIDE_OP)
319 * Divide has an extra target operand (Remainder).
320 * If this extra target is specified, it cannot be converted
321 * to a C-style operator
323 if (AcpiDmIsValidTarget (Target))
325 Child1->Common.OperatorSymbol = NULL;
329 Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
330 Target = Target->Common.Next;
333 /* Parser should ensure there is at least a placeholder target */
340 if (!AcpiDmIsValidTarget (Target))
342 /* Not a valid target (placeholder only, from parser) */
347 * Promote the target up to the first child in the parse
348 * tree. This is done because the target will be output
349 * first, in the form:
350 * <Target> = Operands...
352 AcpiDmPromoteTarget (Op, Target);
354 /* Check operands for conversion to a "Compound Assignment" */
356 switch (Op->Common.AmlOpcode)
358 /* Commutative operators */
361 case AML_MULTIPLY_OP:
366 * For the commutative operators, we can convert to a
367 * compound statement only if at least one (either) operand
368 * is the same as the target.
370 * Add (A, B, A) --> A += B
371 * Add (B, A, A) --> A += B
372 * Add (B, C, A) --> A = (B + C)
374 if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE)) ||
375 (AcpiDmIsTargetAnOperand (Target, Child2, TRUE)))
377 Target->Common.OperatorSymbol =
378 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
380 /* Convert operator to compound assignment */
382 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND;
383 Child1->Common.OperatorSymbol = NULL;
388 /* Non-commutative operators */
390 case AML_SUBTRACT_OP:
393 case AML_SHIFT_LEFT_OP:
394 case AML_SHIFT_RIGHT_OP:
396 * For the non-commutative operators, we can convert to a
397 * compound statement only if the target is the same as the
400 * Subtract (A, B, A) --> A -= B
401 * Subtract (B, A, A) --> A = (B - A)
403 if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE)))
405 Target->Common.OperatorSymbol =
406 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
408 /* Convert operator to compound assignment */
410 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND;
411 Child1->Common.OperatorSymbol = NULL;
421 * If we are within a C-style expression, emit an extra open
422 * paren. Implemented by examining the parent op.
424 switch (Op->Common.Parent->Common.AmlOpcode)
427 case AML_SUBTRACT_OP:
428 case AML_MULTIPLY_OP:
431 case AML_SHIFT_LEFT_OP:
432 case AML_SHIFT_RIGHT_OP:
438 case AML_LGREATER_OP:
442 Op->Common.DisasmFlags |= ACPI_PARSEOP_ASSIGNMENT;
450 /* Normal output for ASL/AML operators with a target operand */
452 Target->Common.OperatorSymbol = " = (";
455 /* Binary operators, no parens */
457 case AML_DECREMENT_OP:
458 case AML_INCREMENT_OP:
463 /* Target is optional, 3rd operand */
465 Target = Child2->Common.Next;
466 if (AcpiDmIsValidTarget (Target))
468 AcpiDmPromoteTarget (Op, Target);
470 if (!Target->Common.OperatorSymbol)
472 Target->Common.OperatorSymbol = " = ";
479 * Target is the 2nd operand.
480 * We know the target is valid, it is not optional.
481 * In the parse tree, simply swap the target with the
482 * source so that the target is processed first.
484 Target = Child1->Common.Next;
490 AcpiDmPromoteTarget (Op, Target);
491 if (!Target->Common.OperatorSymbol)
493 Target->Common.OperatorSymbol = " = ";
499 /* Target is optional, 2nd operand */
501 Target = Child1->Common.Next;
507 if (AcpiDmIsValidTarget (Target))
509 /* Valid target, not a placeholder */
511 AcpiDmPromoteTarget (Op, Target);
512 Target->Common.OperatorSymbol = " = ~";
516 /* No target. Emit this prefix operator immediately */
526 /* All other operators, emit an open paren */
533 /*******************************************************************************
535 * FUNCTION: AcpiDmCloseOperator
537 * PARAMETERS: Op - Current parse object
541 * DESCRIPTION: Closes an operator by adding a closing parentheses if and
542 * when necessary. Called during ascending phase of the
545 ******************************************************************************/
548 AcpiDmCloseOperator (
549 ACPI_PARSE_OBJECT *Op)
552 /* Always emit paren if ASL+ disassembly disabled */
554 if (!AcpiGbl_CstyleDisassembly)
560 /* Check if we need to add an additional closing paren */
562 switch (Op->Common.AmlOpcode)
565 case AML_SUBTRACT_OP:
566 case AML_MULTIPLY_OP:
569 case AML_SHIFT_LEFT_OP:
570 case AML_SHIFT_RIGHT_OP:
576 case AML_LGREATER_OP:
580 /* Emit paren only if this is not a compound assignment */
582 if (Op->Common.DisasmFlags & ACPI_PARSEOP_COMPOUND)
587 /* Emit extra close paren for assignment within an expression */
589 if (Op->Common.DisasmFlags & ACPI_PARSEOP_ASSIGNMENT)
597 /* This is case for unsupported Index() source constants */
599 if (Op->Common.DisasmFlags & ACPI_PARSEOP_CLOSING_PAREN)
605 /* No need for parens for these */
607 case AML_DECREMENT_OP:
608 case AML_INCREMENT_OP:
616 /* Always emit paren for non-ASL+ operators */
624 /*******************************************************************************
626 * FUNCTION: AcpiDmGetCompoundSymbol
628 * PARAMETERS: AslOpcode
630 * RETURN: String containing the compound assignment symbol
632 * DESCRIPTION: Detect opcodes that can be converted to compound assignment,
633 * return the appropriate operator string.
635 ******************************************************************************/
638 AcpiDmGetCompoundSymbol (
650 case AML_SUBTRACT_OP:
654 case AML_MULTIPLY_OP:
666 case AML_SHIFT_LEFT_OP:
670 case AML_SHIFT_RIGHT_OP:
688 /* No operator string for all other opcodes */
696 /*******************************************************************************
698 * FUNCTION: AcpiDmPromoteTarget
700 * PARAMETERS: Op - Operator parse object
701 * Target - Target associate with the Op
705 * DESCRIPTION: Transform the parse tree by moving the target up to the first
708 ******************************************************************************/
711 AcpiDmPromoteTarget (
712 ACPI_PARSE_OBJECT *Op,
713 ACPI_PARSE_OBJECT *Target)
715 ACPI_PARSE_OBJECT *Child;
718 /* Link target directly to the Op as first child */
720 Child = Op->Common.Value.Arg;
721 Op->Common.Value.Arg = Target;
722 Target->Common.Next = Child;
724 /* Find the last peer, it is linked to the target. Unlink it. */
726 while (Child->Common.Next != Target)
728 Child = Child->Common.Next;
731 Child->Common.Next = NULL;
735 /*******************************************************************************
737 * FUNCTION: AcpiDmIsValidTarget
739 * PARAMETERS: Target - Target Op from the parse tree
741 * RETURN: TRUE if the Target is real. FALSE if it is just a placeholder
742 * Op that was inserted by the parser.
744 * DESCRIPTION: Determine if a Target Op is a placeholder Op or a real Target.
745 * In other words, determine if the optional target is used or
746 * not. Note: If Target is NULL, something is seriously wrong,
747 * probably with the parse tree.
749 ******************************************************************************/
752 AcpiDmIsValidTarget (
753 ACPI_PARSE_OBJECT *Target)
761 if ((Target->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
762 (Target->Common.Value.Arg == NULL))
771 /*******************************************************************************
773 * FUNCTION: AcpiDmIsTargetAnOperand
775 * PARAMETERS: Target - Target associated with the expression
776 * Operand - An operand associated with expression
778 * RETURN: TRUE if expression can be converted to a compound assignment.
781 * DESCRIPTION: Determine if the Target duplicates the operand, in order to
782 * detect if the expression can be converted to a compound
783 * assigment. (+=, *=, etc.)
785 ******************************************************************************/
788 AcpiDmIsTargetAnOperand (
789 ACPI_PARSE_OBJECT *Target,
790 ACPI_PARSE_OBJECT *Operand,
793 const ACPI_OPCODE_INFO *OpInfo;
798 * Opcodes must match. Note: ignoring the difference between nameseg
799 * and namepath for now. May be needed later.
801 if (Target->Common.AmlOpcode != Operand->Common.AmlOpcode)
806 /* Nodes should match, even if they are NULL */
808 if (Target->Common.Node != Operand->Common.Node)
813 /* Determine if a child exists */
815 OpInfo = AcpiPsGetOpcodeInfo (Operand->Common.AmlOpcode);
816 if (OpInfo->Flags & AML_HAS_ARGS)
818 Same = AcpiDmIsTargetAnOperand (Target->Common.Value.Arg,
819 Operand->Common.Value.Arg, FALSE);
826 /* Check the next peer, as long as we are not at the top level */
831 Same = AcpiDmIsTargetAnOperand (Target->Common.Next,
832 Operand->Common.Next, FALSE);
839 /* Supress the duplicate operand at the top-level */
843 Operand->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;