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.
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);
341 * Check for possible conversion to a "Compound Assignment".
343 * Determine if either operand is the same as the target
344 * and display compound assignment operator and other operand.
346 if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE)) ||
347 (AcpiDmIsTargetAnOperand (Target, Child2, TRUE)))
349 Target->Common.OperatorSymbol =
350 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
352 /* Convert operator to compound assignment */
354 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND;
355 Child1->Common.OperatorSymbol = NULL;
360 * If we are within a C-style expression, emit an extra open
361 * paren. Implemented by examining the parent op.
363 switch (Op->Common.Parent->Common.AmlOpcode)
366 case AML_SUBTRACT_OP:
367 case AML_MULTIPLY_OP:
370 case AML_SHIFT_LEFT_OP:
371 case AML_SHIFT_RIGHT_OP:
377 case AML_LGREATER_OP:
381 Op->Common.DisasmFlags |= ACPI_PARSEOP_ASSIGNMENT;
389 /* Normal output for ASL/AML operators with a target operand */
391 Target->Common.OperatorSymbol = " = (";
394 /* Binary operators, no parens */
396 case AML_DECREMENT_OP:
397 case AML_INCREMENT_OP:
403 /* Target is optional, 3rd operand */
405 Target = Child2->Common.Next;
406 if (AcpiDmIsValidTarget (Target))
408 AcpiDmPromoteTarget (Op, Target);
410 if (!Target->Common.OperatorSymbol)
412 Target->Common.OperatorSymbol = " = ";
420 * Target is the 2nd operand.
421 * We know the target is valid, it is not optional.
422 * In the parse tree, simply swap the target with the
423 * source so that the target is processed first.
425 Target = Child1->Common.Next;
426 AcpiDmPromoteTarget (Op, Target);
428 if (!Target->Common.OperatorSymbol)
430 Target->Common.OperatorSymbol = " = ";
436 /* Target is optional, 2nd operand */
438 Target = Child1->Common.Next;
444 if (AcpiDmIsValidTarget (Target))
446 /* Valid target, not a placeholder */
448 AcpiDmPromoteTarget (Op, Target);
449 Target->Common.OperatorSymbol = " = ~";
453 /* No target. Emit this prefix operator immediately */
463 /* All other operators, emit an open paren */
470 /*******************************************************************************
472 * FUNCTION: AcpiDmCloseOperator
474 * PARAMETERS: Op - Current parse object
478 * DESCRIPTION: Closes an operator by adding a closing parentheses if and
479 * when necessary. Called during ascending phase of the
482 ******************************************************************************/
485 AcpiDmCloseOperator (
486 ACPI_PARSE_OBJECT *Op)
489 /* Always emit paren if ASL+ disassembly disabled */
491 if (!AcpiGbl_CstyleDisassembly)
497 /* Check if we need to add an additional closing paren */
499 switch (Op->Common.AmlOpcode)
502 case AML_SUBTRACT_OP:
503 case AML_MULTIPLY_OP:
506 case AML_SHIFT_LEFT_OP:
507 case AML_SHIFT_RIGHT_OP:
513 case AML_LGREATER_OP:
517 /* Emit paren only if this is not a compound assignment */
519 if (Op->Common.DisasmFlags & ACPI_PARSEOP_COMPOUND)
524 /* Emit extra close paren for assignment within an expression */
526 if (Op->Common.DisasmFlags & ACPI_PARSEOP_ASSIGNMENT)
533 /* No need for parens for these */
538 case AML_DECREMENT_OP:
539 case AML_INCREMENT_OP:
547 /* Always emit paren for non-ASL+ operators */
555 /*******************************************************************************
557 * FUNCTION: AcpiDmGetCompoundSymbol
559 * PARAMETERS: AslOpcode
561 * RETURN: String containing the compound assignment symbol
563 * DESCRIPTION: Detect opcodes that can be converted to compound assignment,
564 * return the appropriate operator string.
566 ******************************************************************************/
569 AcpiDmGetCompoundSymbol (
581 case AML_SUBTRACT_OP:
585 case AML_MULTIPLY_OP:
597 case AML_SHIFT_LEFT_OP:
601 case AML_SHIFT_RIGHT_OP:
619 /* No operator string for all other opcodes */
627 /*******************************************************************************
629 * FUNCTION: AcpiDmPromoteTarget
631 * PARAMETERS: Op - Operator parse object
632 * Target - Target associate with the Op
636 * DESCRIPTION: Transform the parse tree by moving the target up to the first
639 ******************************************************************************/
642 AcpiDmPromoteTarget (
643 ACPI_PARSE_OBJECT *Op,
644 ACPI_PARSE_OBJECT *Target)
646 ACPI_PARSE_OBJECT *Child;
649 /* Link target directly to the Op as first child */
651 Child = Op->Common.Value.Arg;
652 Op->Common.Value.Arg = Target;
653 Target->Common.Next = Child;
655 /* Find the last peer, it is linked to the target. Unlink it. */
657 while (Child->Common.Next != Target)
659 Child = Child->Common.Next;
662 Child->Common.Next = NULL;
666 /*******************************************************************************
668 * FUNCTION: AcpiDmIsValidTarget
670 * PARAMETERS: Target - Target Op from the parse tree
672 * RETURN: TRUE if the Target is real. FALSE if it is just a placeholder
673 * Op that was inserted by the parser.
675 * DESCRIPTION: Determine if a Target Op is a placeholder Op or a real Target.
676 * In other words, determine if the optional target is used or
679 ******************************************************************************/
682 AcpiDmIsValidTarget (
683 ACPI_PARSE_OBJECT *Target)
686 if ((Target->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
687 (Target->Common.Value.Arg == NULL))
696 /*******************************************************************************
698 * FUNCTION: AcpiDmIsTargetAnOperand
700 * PARAMETERS: Target - Target associated with the expression
701 * Operand - An operand associated with expression
703 * RETURN: TRUE if expression can be converted to a compound assignment.
706 * DESCRIPTION: Determine if the Target duplicates the operand, in order to
707 * detect if the expression can be converted to a compound
708 * assigment. (+=, *=, etc.)
710 ******************************************************************************/
713 AcpiDmIsTargetAnOperand (
714 ACPI_PARSE_OBJECT *Target,
715 ACPI_PARSE_OBJECT *Operand,
718 const ACPI_OPCODE_INFO *OpInfo;
723 * Opcodes must match. Note: ignoring the difference between nameseg
724 * and namepath for now. May be needed later.
726 if (Target->Common.AmlOpcode != Operand->Common.AmlOpcode)
731 /* Nodes should match, even if they are NULL */
733 if (Target->Common.Node != Operand->Common.Node)
738 /* Determine if a child exists */
740 OpInfo = AcpiPsGetOpcodeInfo (Operand->Common.AmlOpcode);
741 if (OpInfo->Flags & AML_HAS_ARGS)
743 Same = AcpiDmIsTargetAnOperand (Target->Common.Value.Arg,
744 Operand->Common.Value.Arg, FALSE);
751 /* Check the next peer, as long as we are not at the top level */
756 Same = AcpiDmIsTargetAnOperand (Target->Common.Next,
757 Operand->Common.Next, FALSE);
764 /* Supress the duplicate operand at the top-level */
768 Operand->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;