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.
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>
51 #ifdef ACPI_DISASSEMBLER
53 #define _COMPONENT ACPI_CA_DEBUGGER
54 ACPI_MODULE_NAME ("dmcstyle")
57 /* Local prototypes */
60 AcpiDmGetCompoundSymbol (
65 ACPI_PARSE_OBJECT *Op,
66 ACPI_PARSE_OBJECT *Target);
70 ACPI_PARSE_OBJECT *Op);
73 AcpiDmIsTargetAnOperand (
74 ACPI_PARSE_OBJECT *Target,
75 ACPI_PARSE_OBJECT *Operand,
79 /*******************************************************************************
81 * FUNCTION: AcpiDmCheckForSymbolicOpcode
83 * PARAMETERS: Op - Current parse object
84 * Walk - Current parse tree walk info
86 * RETURN: TRUE if opcode can be converted to symbolic, FALSE otherwise
88 * DESCRIPTION: This is the main code that implements disassembly of AML code
89 * to C-style operators. Called during descending phase of the
92 ******************************************************************************/
95 AcpiDmCheckForSymbolicOpcode (
96 ACPI_PARSE_OBJECT *Op,
97 ACPI_OP_WALK_INFO *Info)
99 char *OperatorSymbol = NULL;
100 ACPI_PARSE_OBJECT *Child1;
101 ACPI_PARSE_OBJECT *Child2;
102 ACPI_PARSE_OBJECT *Target;
105 /* Exit immediately if ASL+ not enabled */
107 if (!AcpiGbl_CstyleDisassembly)
112 /* Get the first operand */
114 Child1 = AcpiPsGetArg (Op, 0);
120 /* Get the second operand */
122 Child2 = Child1->Common.Next;
124 /* Setup the operator string for this opcode */
126 switch (Op->Common.AmlOpcode)
129 OperatorSymbol = " + ";
132 case AML_SUBTRACT_OP:
133 OperatorSymbol = " - ";
136 case AML_MULTIPLY_OP:
137 OperatorSymbol = " * ";
141 OperatorSymbol = " / ";
145 OperatorSymbol = " % ";
148 case AML_SHIFT_LEFT_OP:
149 OperatorSymbol = " << ";
152 case AML_SHIFT_RIGHT_OP:
153 OperatorSymbol = " >> ";
157 OperatorSymbol = " & ";
161 OperatorSymbol = " | ";
165 OperatorSymbol = " ^ ";
168 /* Logical operators, no target */
171 OperatorSymbol = " && ";
175 OperatorSymbol = " == ";
178 case AML_LGREATER_OP:
179 OperatorSymbol = " > ";
183 OperatorSymbol = " < ";
187 OperatorSymbol = " || ";
192 * Check for the LNOT sub-opcodes. These correspond to
193 * LNotEqual, LLessEqual, and LGreaterEqual. There are
194 * no actual AML opcodes for these operators.
196 switch (Child1->Common.AmlOpcode)
199 OperatorSymbol = " != ";
202 case AML_LGREATER_OP:
203 OperatorSymbol = " <= ";
207 OperatorSymbol = " >= ";
212 /* Unary LNOT case, emit "!" immediately */
218 Child1->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX;
219 Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX;
221 /* Save symbol string in the next child (not peer) */
223 Child2 = AcpiPsGetArg (Child1, 0);
229 Child2->Common.OperatorSymbol = OperatorSymbol;
234 Child1->Common.OperatorSymbol = " [";
235 Child2->Common.OperatorSymbol = "]";
239 /* Unary operators */
241 case AML_DECREMENT_OP:
242 OperatorSymbol = "--";
245 case AML_INCREMENT_OP:
246 OperatorSymbol = "++";
251 OperatorSymbol = NULL;
258 if (Child1->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX)
264 * This is the key to how the disassembly of the C-style operators
265 * works. We save the operator symbol in the first child, thus
266 * deferring symbol output until after the first operand has been
269 if (!Child1->Common.OperatorSymbol)
271 Child1->Common.OperatorSymbol = OperatorSymbol;
275 * Check for a valid target as the 3rd (or sometimes 2nd) operand
277 * Compound assignment operator support:
278 * Attempt to optimize constructs of the form:
279 * Add (Local1, 0xFF, Local1)
283 * Only the math operators and Store() have a target.
284 * Logicals have no target.
286 switch (Op->Common.AmlOpcode)
289 case AML_SUBTRACT_OP:
290 case AML_MULTIPLY_OP:
293 case AML_SHIFT_LEFT_OP:
294 case AML_SHIFT_RIGHT_OP:
299 /* Target is 3rd operand */
301 Target = Child2->Common.Next;
302 if (Op->Common.AmlOpcode == AML_DIVIDE_OP)
305 * Divide has an extra target operand (Remainder).
306 * If this extra target is specified, it cannot be converted
307 * to a C-style operator
309 if (AcpiDmIsValidTarget (Target))
311 Child1->Common.OperatorSymbol = NULL;
315 Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
316 Target = Target->Common.Next;
319 /* Parser should ensure there is at least a placeholder target */
326 if (!AcpiDmIsValidTarget (Target))
328 /* Not a valid target (placeholder only, from parser) */
333 * Promote the target up to the first child in the parse
334 * tree. This is done because the target will be output
335 * first, in the form:
336 * <Target> = Operands...
338 AcpiDmPromoteTarget (Op, Target);
340 /* Check operands for conversion to a "Compound Assignment" */
342 switch (Op->Common.AmlOpcode)
344 /* Commutative operators */
347 case AML_MULTIPLY_OP:
352 * For the commutative operators, we can convert to a
353 * compound statement only if at least one (either) operand
354 * is the same as the target.
356 * Add (A, B, A) --> A += B
357 * Add (B, A, A) --> A += B
358 * Add (B, C, A) --> A = (B + C)
360 if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE)) ||
361 (AcpiDmIsTargetAnOperand (Target, Child2, TRUE)))
363 Target->Common.OperatorSymbol =
364 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
366 /* Convert operator to compound assignment */
368 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND;
369 Child1->Common.OperatorSymbol = NULL;
374 /* Non-commutative operators */
376 case AML_SUBTRACT_OP:
379 case AML_SHIFT_LEFT_OP:
380 case AML_SHIFT_RIGHT_OP:
382 * For the non-commutative operators, we can convert to a
383 * compound statement only if the target is the same as the
386 * Subtract (A, B, A) --> A -= B
387 * Subtract (B, A, A) --> A = (B - A)
389 if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE)))
391 Target->Common.OperatorSymbol =
392 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
394 /* Convert operator to compound assignment */
396 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND;
397 Child1->Common.OperatorSymbol = NULL;
407 * If we are within a C-style expression, emit an extra open
408 * paren. Implemented by examining the parent op.
410 switch (Op->Common.Parent->Common.AmlOpcode)
413 case AML_SUBTRACT_OP:
414 case AML_MULTIPLY_OP:
417 case AML_SHIFT_LEFT_OP:
418 case AML_SHIFT_RIGHT_OP:
424 case AML_LGREATER_OP:
428 Op->Common.DisasmFlags |= ACPI_PARSEOP_ASSIGNMENT;
436 /* Normal output for ASL/AML operators with a target operand */
438 Target->Common.OperatorSymbol = " = (";
441 /* Binary operators, no parens */
443 case AML_DECREMENT_OP:
444 case AML_INCREMENT_OP:
450 /* Target is optional, 3rd operand */
452 Target = Child2->Common.Next;
453 if (AcpiDmIsValidTarget (Target))
455 AcpiDmPromoteTarget (Op, Target);
457 if (!Target->Common.OperatorSymbol)
459 Target->Common.OperatorSymbol = " = ";
467 * Target is the 2nd operand.
468 * We know the target is valid, it is not optional.
469 * In the parse tree, simply swap the target with the
470 * source so that the target is processed first.
472 Target = Child1->Common.Next;
478 AcpiDmPromoteTarget (Op, Target);
479 if (!Target->Common.OperatorSymbol)
481 Target->Common.OperatorSymbol = " = ";
487 /* Target is optional, 2nd operand */
489 Target = Child1->Common.Next;
495 if (AcpiDmIsValidTarget (Target))
497 /* Valid target, not a placeholder */
499 AcpiDmPromoteTarget (Op, Target);
500 Target->Common.OperatorSymbol = " = ~";
504 /* No target. Emit this prefix operator immediately */
514 /* All other operators, emit an open paren */
521 /*******************************************************************************
523 * FUNCTION: AcpiDmCloseOperator
525 * PARAMETERS: Op - Current parse object
529 * DESCRIPTION: Closes an operator by adding a closing parentheses if and
530 * when necessary. Called during ascending phase of the
533 ******************************************************************************/
536 AcpiDmCloseOperator (
537 ACPI_PARSE_OBJECT *Op)
540 /* Always emit paren if ASL+ disassembly disabled */
542 if (!AcpiGbl_CstyleDisassembly)
548 /* Check if we need to add an additional closing paren */
550 switch (Op->Common.AmlOpcode)
553 case AML_SUBTRACT_OP:
554 case AML_MULTIPLY_OP:
557 case AML_SHIFT_LEFT_OP:
558 case AML_SHIFT_RIGHT_OP:
564 case AML_LGREATER_OP:
568 /* Emit paren only if this is not a compound assignment */
570 if (Op->Common.DisasmFlags & ACPI_PARSEOP_COMPOUND)
575 /* Emit extra close paren for assignment within an expression */
577 if (Op->Common.DisasmFlags & ACPI_PARSEOP_ASSIGNMENT)
584 /* No need for parens for these */
589 case AML_DECREMENT_OP:
590 case AML_INCREMENT_OP:
598 /* Always emit paren for non-ASL+ operators */
606 /*******************************************************************************
608 * FUNCTION: AcpiDmGetCompoundSymbol
610 * PARAMETERS: AslOpcode
612 * RETURN: String containing the compound assignment symbol
614 * DESCRIPTION: Detect opcodes that can be converted to compound assignment,
615 * return the appropriate operator string.
617 ******************************************************************************/
620 AcpiDmGetCompoundSymbol (
632 case AML_SUBTRACT_OP:
636 case AML_MULTIPLY_OP:
648 case AML_SHIFT_LEFT_OP:
652 case AML_SHIFT_RIGHT_OP:
670 /* No operator string for all other opcodes */
678 /*******************************************************************************
680 * FUNCTION: AcpiDmPromoteTarget
682 * PARAMETERS: Op - Operator parse object
683 * Target - Target associate with the Op
687 * DESCRIPTION: Transform the parse tree by moving the target up to the first
690 ******************************************************************************/
693 AcpiDmPromoteTarget (
694 ACPI_PARSE_OBJECT *Op,
695 ACPI_PARSE_OBJECT *Target)
697 ACPI_PARSE_OBJECT *Child;
700 /* Link target directly to the Op as first child */
702 Child = Op->Common.Value.Arg;
703 Op->Common.Value.Arg = Target;
704 Target->Common.Next = Child;
706 /* Find the last peer, it is linked to the target. Unlink it. */
708 while (Child->Common.Next != Target)
710 Child = Child->Common.Next;
713 Child->Common.Next = NULL;
717 /*******************************************************************************
719 * FUNCTION: AcpiDmIsValidTarget
721 * PARAMETERS: Target - Target Op from the parse tree
723 * RETURN: TRUE if the Target is real. FALSE if it is just a placeholder
724 * Op that was inserted by the parser.
726 * DESCRIPTION: Determine if a Target Op is a placeholder Op or a real Target.
727 * In other words, determine if the optional target is used or
728 * not. Note: If Target is NULL, something is seriously wrong,
729 * probably with the parse tree.
731 ******************************************************************************/
734 AcpiDmIsValidTarget (
735 ACPI_PARSE_OBJECT *Target)
743 if ((Target->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
744 (Target->Common.Value.Arg == NULL))
753 /*******************************************************************************
755 * FUNCTION: AcpiDmIsTargetAnOperand
757 * PARAMETERS: Target - Target associated with the expression
758 * Operand - An operand associated with expression
760 * RETURN: TRUE if expression can be converted to a compound assignment.
763 * DESCRIPTION: Determine if the Target duplicates the operand, in order to
764 * detect if the expression can be converted to a compound
765 * assigment. (+=, *=, etc.)
767 ******************************************************************************/
770 AcpiDmIsTargetAnOperand (
771 ACPI_PARSE_OBJECT *Target,
772 ACPI_PARSE_OBJECT *Operand,
775 const ACPI_OPCODE_INFO *OpInfo;
780 * Opcodes must match. Note: ignoring the difference between nameseg
781 * and namepath for now. May be needed later.
783 if (Target->Common.AmlOpcode != Operand->Common.AmlOpcode)
788 /* Nodes should match, even if they are NULL */
790 if (Target->Common.Node != Operand->Common.Node)
795 /* Determine if a child exists */
797 OpInfo = AcpiPsGetOpcodeInfo (Operand->Common.AmlOpcode);
798 if (OpInfo->Flags & AML_HAS_ARGS)
800 Same = AcpiDmIsTargetAnOperand (Target->Common.Value.Arg,
801 Operand->Common.Value.Arg, FALSE);
808 /* Check the next peer, as long as we are not at the top level */
813 Same = AcpiDmIsTargetAnOperand (Target->Common.Next,
814 Operand->Common.Next, FALSE);
821 /* Supress the duplicate operand at the top-level */
825 Operand->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;