1 /******************************************************************************* 2 * 3 * Module Name: dmcstyle - Support for C-style operator disassembly 4 * 5 ******************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2016, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 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. 25 * 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. 29 * 30 * NO WARRANTY 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. 42 */ 43 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/acdebug.h> 49 50 51 #define _COMPONENT ACPI_CA_DEBUGGER 52 ACPI_MODULE_NAME ("dmcstyle") 53 54 55 /* Local prototypes */ 56 57 static char * 58 AcpiDmGetCompoundSymbol ( 59 UINT16 AslOpcode); 60 61 static void 62 AcpiDmPromoteTarget ( 63 ACPI_PARSE_OBJECT *Op, 64 ACPI_PARSE_OBJECT *Target); 65 66 static BOOLEAN 67 AcpiDmIsValidTarget ( 68 ACPI_PARSE_OBJECT *Op); 69 70 static BOOLEAN 71 AcpiDmIsTargetAnOperand ( 72 ACPI_PARSE_OBJECT *Target, 73 ACPI_PARSE_OBJECT *Operand, 74 BOOLEAN TopLevel); 75 76 77 /******************************************************************************* 78 * 79 * FUNCTION: AcpiDmCheckForSymbolicOpcode 80 * 81 * PARAMETERS: Op - Current parse object 82 * Walk - Current parse tree walk info 83 * 84 * RETURN: TRUE if opcode can be converted to symbolic, FALSE otherwise 85 * 86 * DESCRIPTION: This is the main code that implements disassembly of AML code 87 * to C-style operators. Called during descending phase of the 88 * parse tree walk. 89 * 90 ******************************************************************************/ 91 92 BOOLEAN 93 AcpiDmCheckForSymbolicOpcode ( 94 ACPI_PARSE_OBJECT *Op, 95 ACPI_OP_WALK_INFO *Info) 96 { 97 char *OperatorSymbol = NULL; 98 ACPI_PARSE_OBJECT *Child1; 99 ACPI_PARSE_OBJECT *Child2; 100 ACPI_PARSE_OBJECT *Target; 101 ACPI_PARSE_OBJECT *GrandChild1; 102 ACPI_PARSE_OBJECT *GrandChild2; 103 ACPI_PARSE_OBJECT *GrandTarget = NULL; 104 105 106 /* Exit immediately if ASL+ not enabled */ 107 108 if (!AcpiGbl_CstyleDisassembly) 109 { 110 return (FALSE); 111 } 112 113 /* Check for a non-ASL+ statement, propagate the flag */ 114 115 if (Op->Common.Parent->Common.DisasmFlags & ACPI_PARSEOP_LEGACY_ASL_ONLY) 116 { 117 Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY; 118 return (FALSE); 119 } 120 121 /* Get the first operand */ 122 123 Child1 = AcpiPsGetArg (Op, 0); 124 if (!Child1) 125 { 126 return (FALSE); 127 } 128 129 /* Get the second operand */ 130 131 Child2 = Child1->Common.Next; 132 133 /* Setup the operator string for this opcode */ 134 135 switch (Op->Common.AmlOpcode) 136 { 137 case AML_ADD_OP: 138 OperatorSymbol = " + "; 139 break; 140 141 case AML_SUBTRACT_OP: 142 OperatorSymbol = " - "; 143 break; 144 145 case AML_MULTIPLY_OP: 146 OperatorSymbol = " * "; 147 break; 148 149 case AML_DIVIDE_OP: 150 OperatorSymbol = " / "; 151 break; 152 153 case AML_MOD_OP: 154 OperatorSymbol = " % "; 155 break; 156 157 case AML_SHIFT_LEFT_OP: 158 OperatorSymbol = " << "; 159 break; 160 161 case AML_SHIFT_RIGHT_OP: 162 OperatorSymbol = " >> "; 163 break; 164 165 case AML_BIT_AND_OP: 166 OperatorSymbol = " & "; 167 break; 168 169 case AML_BIT_OR_OP: 170 OperatorSymbol = " | "; 171 break; 172 173 case AML_BIT_XOR_OP: 174 OperatorSymbol = " ^ "; 175 break; 176 177 /* Logical operators, no target */ 178 179 case AML_LAND_OP: 180 OperatorSymbol = " && "; 181 break; 182 183 case AML_LEQUAL_OP: 184 OperatorSymbol = " == "; 185 break; 186 187 case AML_LGREATER_OP: 188 OperatorSymbol = " > "; 189 break; 190 191 case AML_LLESS_OP: 192 OperatorSymbol = " < "; 193 break; 194 195 case AML_LOR_OP: 196 OperatorSymbol = " || "; 197 break; 198 199 case AML_LNOT_OP: 200 /* 201 * Check for the LNOT sub-opcodes. These correspond to 202 * LNotEqual, LLessEqual, and LGreaterEqual. There are 203 * no actual AML opcodes for these operators. 204 */ 205 switch (Child1->Common.AmlOpcode) 206 { 207 case AML_LEQUAL_OP: 208 OperatorSymbol = " != "; 209 break; 210 211 case AML_LGREATER_OP: 212 OperatorSymbol = " <= "; 213 break; 214 215 case AML_LLESS_OP: 216 OperatorSymbol = " >= "; 217 break; 218 219 default: 220 221 /* Unary LNOT case, emit "!" immediately */ 222 223 AcpiOsPrintf ("!"); 224 return (TRUE); 225 } 226 227 Child1->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX; 228 Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX; 229 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT; 230 231 /* Save symbol string in the next child (not peer) */ 232 233 Child2 = AcpiPsGetArg (Child1, 0); 234 if (!Child2) 235 { 236 return (FALSE); 237 } 238 239 Child2->Common.OperatorSymbol = OperatorSymbol; 240 return (TRUE); 241 242 case AML_INDEX_OP: 243 /* 244 * Check for constant source operand. Note: although technically 245 * legal syntax, the iASL compiler does not support this with 246 * the symbolic operators for Index(). It doesn't make sense to 247 * use Index() with a constant anyway. 248 */ 249 if ((Child1->Common.AmlOpcode == AML_STRING_OP) || 250 (Child1->Common.AmlOpcode == AML_BUFFER_OP) || 251 (Child1->Common.AmlOpcode == AML_PACKAGE_OP) || 252 (Child1->Common.AmlOpcode == AML_VAR_PACKAGE_OP)) 253 { 254 Op->Common.DisasmFlags |= ACPI_PARSEOP_CLOSING_PAREN; 255 return (FALSE); 256 } 257 258 /* Index operator is [] */ 259 260 Child1->Common.OperatorSymbol = " ["; 261 Child2->Common.OperatorSymbol = "]"; 262 break; 263 264 /* Unary operators */ 265 266 case AML_DECREMENT_OP: 267 OperatorSymbol = "--"; 268 break; 269 270 case AML_INCREMENT_OP: 271 OperatorSymbol = "++"; 272 break; 273 274 case AML_BIT_NOT_OP: 275 case AML_STORE_OP: 276 OperatorSymbol = NULL; 277 break; 278 279 default: 280 return (FALSE); 281 } 282 283 if (Child1->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX) 284 { 285 return (TRUE); 286 } 287 288 /* 289 * This is the key to how the disassembly of the C-style operators 290 * works. We save the operator symbol in the first child, thus 291 * deferring symbol output until after the first operand has been 292 * emitted. 293 */ 294 if (!Child1->Common.OperatorSymbol) 295 { 296 Child1->Common.OperatorSymbol = OperatorSymbol; 297 } 298 299 /* 300 * Check for a valid target as the 3rd (or sometimes 2nd) operand 301 * 302 * Compound assignment operator support: 303 * Attempt to optimize constructs of the form: 304 * Add (Local1, 0xFF, Local1) 305 * to: 306 * Local1 += 0xFF 307 * 308 * Only the math operators and Store() have a target. 309 * Logicals have no target. 310 */ 311 switch (Op->Common.AmlOpcode) 312 { 313 case AML_ADD_OP: 314 case AML_SUBTRACT_OP: 315 case AML_MULTIPLY_OP: 316 case AML_DIVIDE_OP: 317 case AML_MOD_OP: 318 case AML_SHIFT_LEFT_OP: 319 case AML_SHIFT_RIGHT_OP: 320 case AML_BIT_AND_OP: 321 case AML_BIT_OR_OP: 322 case AML_BIT_XOR_OP: 323 324 /* Target is 3rd operand */ 325 326 Target = Child2->Common.Next; 327 if (Op->Common.AmlOpcode == AML_DIVIDE_OP) 328 { 329 /* 330 * Divide has an extra target operand (Remainder). 331 * If this extra target is specified, it cannot be converted 332 * to a C-style operator 333 */ 334 if (AcpiDmIsValidTarget (Target)) 335 { 336 Child1->Common.OperatorSymbol = NULL; 337 Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY; 338 return (FALSE); 339 } 340 341 Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 342 Target = Target->Common.Next; 343 } 344 345 /* Parser should ensure there is at least a placeholder target */ 346 347 if (!Target) 348 { 349 return (FALSE); 350 } 351 352 if (!AcpiDmIsValidTarget (Target)) 353 { 354 if (Op->Common.Parent->Common.AmlOpcode == AML_STORE_OP) 355 { 356 Op->Common.DisasmFlags = 0; 357 Child1->Common.OperatorSymbol = NULL; 358 return (FALSE); 359 } 360 361 /* Not a valid target (placeholder only, from parser) */ 362 break; 363 } 364 365 /* 366 * Promote the target up to the first child in the parse 367 * tree. This is done because the target will be output 368 * first, in the form: 369 * <Target> = Operands... 370 */ 371 AcpiDmPromoteTarget (Op, Target); 372 373 /* Check operands for conversion to a "Compound Assignment" */ 374 375 switch (Op->Common.AmlOpcode) 376 { 377 /* Commutative operators */ 378 379 case AML_ADD_OP: 380 case AML_MULTIPLY_OP: 381 case AML_BIT_AND_OP: 382 case AML_BIT_OR_OP: 383 case AML_BIT_XOR_OP: 384 /* 385 * For the commutative operators, we can convert to a 386 * compound statement only if at least one (either) operand 387 * is the same as the target. 388 * 389 * Add (A, B, A) --> A += B 390 * Add (B, A, A) --> A += B 391 * Add (B, C, A) --> A = (B + C) 392 */ 393 if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE)) || 394 (AcpiDmIsTargetAnOperand (Target, Child2, TRUE))) 395 { 396 Target->Common.OperatorSymbol = 397 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode); 398 399 /* Convert operator to compound assignment */ 400 401 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT; 402 Child1->Common.OperatorSymbol = NULL; 403 return (TRUE); 404 } 405 break; 406 407 /* Non-commutative operators */ 408 409 case AML_SUBTRACT_OP: 410 case AML_DIVIDE_OP: 411 case AML_MOD_OP: 412 case AML_SHIFT_LEFT_OP: 413 case AML_SHIFT_RIGHT_OP: 414 /* 415 * For the non-commutative operators, we can convert to a 416 * compound statement only if the target is the same as the 417 * first operand. 418 * 419 * Subtract (A, B, A) --> A -= B 420 * Subtract (B, A, A) --> A = (B - A) 421 */ 422 if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE))) 423 { 424 Target->Common.OperatorSymbol = 425 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode); 426 427 /* Convert operator to compound assignment */ 428 429 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT; 430 Child1->Common.OperatorSymbol = NULL; 431 return (TRUE); 432 } 433 break; 434 435 default: 436 break; 437 } 438 439 /* 440 * If we are within a C-style expression, emit an extra open 441 * paren. Implemented by examining the parent op. 442 */ 443 switch (Op->Common.Parent->Common.AmlOpcode) 444 { 445 case AML_ADD_OP: 446 case AML_SUBTRACT_OP: 447 case AML_MULTIPLY_OP: 448 case AML_DIVIDE_OP: 449 case AML_MOD_OP: 450 case AML_SHIFT_LEFT_OP: 451 case AML_SHIFT_RIGHT_OP: 452 case AML_BIT_AND_OP: 453 case AML_BIT_OR_OP: 454 case AML_BIT_XOR_OP: 455 case AML_LAND_OP: 456 case AML_LEQUAL_OP: 457 case AML_LGREATER_OP: 458 case AML_LLESS_OP: 459 case AML_LOR_OP: 460 461 Op->Common.DisasmFlags |= ACPI_PARSEOP_ASSIGNMENT; 462 AcpiOsPrintf ("("); 463 break; 464 465 default: 466 break; 467 } 468 469 /* Normal output for ASL/AML operators with a target operand */ 470 471 Target->Common.OperatorSymbol = " = ("; 472 return (TRUE); 473 474 /* Binary operators, no parens */ 475 476 case AML_DECREMENT_OP: 477 case AML_INCREMENT_OP: 478 return (TRUE); 479 480 case AML_INDEX_OP: 481 482 /* Target is optional, 3rd operand */ 483 484 Target = Child2->Common.Next; 485 if (AcpiDmIsValidTarget (Target)) 486 { 487 AcpiDmPromoteTarget (Op, Target); 488 489 if (!Target->Common.OperatorSymbol) 490 { 491 Target->Common.OperatorSymbol = " = "; 492 } 493 } 494 return (TRUE); 495 496 case AML_STORE_OP: 497 /* 498 * Target is the 2nd operand. 499 * We know the target is valid, it is not optional. 500 * 501 * The following block implements "Ignore conversion if a store 502 * is followed by a math/bit operator that has no target". Used 503 * only for the ASL test suite. 504 */ 505 if (!AcpiGbl_DoDisassemblerOptimizations) 506 { 507 switch (Child1->Common.AmlOpcode) 508 { 509 /* This operator has two operands and two targets */ 510 511 case AML_DIVIDE_OP: 512 513 GrandChild1 = Child1->Common.Value.Arg; 514 GrandChild2 = GrandChild1->Common.Next; 515 GrandTarget = GrandChild2->Common.Next; 516 517 if (GrandTarget && !AcpiDmIsValidTarget (GrandTarget)) 518 { 519 Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY; 520 return (FALSE); 521 } 522 GrandTarget = GrandTarget->Common.Next; 523 break; 524 525 case AML_ADD_OP: 526 case AML_SUBTRACT_OP: 527 case AML_MULTIPLY_OP: 528 case AML_MOD_OP: 529 case AML_SHIFT_LEFT_OP: 530 case AML_SHIFT_RIGHT_OP: 531 case AML_BIT_AND_OP: 532 case AML_BIT_OR_OP: 533 case AML_BIT_XOR_OP: 534 case AML_INDEX_OP: 535 536 /* These operators have two operands and a target */ 537 538 GrandChild1 = Child1->Common.Value.Arg; 539 GrandChild2 = GrandChild1->Common.Next; 540 GrandTarget = GrandChild2->Common.Next; 541 break; 542 543 case AML_BIT_NOT_OP: 544 545 /* This operator has one operand and a target */ 546 547 GrandChild1 = Child1->Common.Value.Arg; 548 GrandTarget = GrandChild1->Common.Next; 549 break; 550 551 default: 552 break; 553 } 554 555 if (GrandTarget && !AcpiDmIsValidTarget (GrandTarget)) 556 { 557 Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY; 558 return (FALSE); 559 } 560 } 561 562 /* 563 * In the parse tree, simply swap the target with the 564 * source so that the target is processed first. 565 */ 566 Target = Child1->Common.Next; 567 if (!Target) 568 { 569 return (FALSE); 570 } 571 572 AcpiDmPromoteTarget (Op, Target); 573 if (!Target->Common.OperatorSymbol) 574 { 575 Target->Common.OperatorSymbol = " = "; 576 } 577 return (TRUE); 578 579 case AML_BIT_NOT_OP: 580 581 /* Target is optional, 2nd operand */ 582 583 Target = Child1->Common.Next; 584 if (!Target) 585 { 586 return (FALSE); 587 } 588 589 if (AcpiDmIsValidTarget (Target)) 590 { 591 /* Valid target, not a placeholder */ 592 593 AcpiDmPromoteTarget (Op, Target); 594 Target->Common.OperatorSymbol = " = ~"; 595 } 596 else 597 { 598 /* No target. Emit this prefix operator immediately */ 599 600 AcpiOsPrintf ("~"); 601 } 602 return (TRUE); 603 604 default: 605 break; 606 } 607 608 /* 609 * Nodes marked with ACPI_PARSEOP_PARAMLIST don't need a parens 610 * output here. We also need to check the parent to see if this op 611 * is part of a compound test (!=, >=, <=). 612 */ 613 if ((Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) || 614 ((Op->Common.Parent->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) && 615 (Op->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX))) 616 { 617 /* Do Nothing. Paren already generated */ 618 return (TRUE); 619 } 620 621 /* All other operators, emit an open paren */ 622 623 AcpiOsPrintf ("("); 624 return (TRUE); 625 } 626 627 628 /******************************************************************************* 629 * 630 * FUNCTION: AcpiDmCloseOperator 631 * 632 * PARAMETERS: Op - Current parse object 633 * 634 * RETURN: None 635 * 636 * DESCRIPTION: Closes an operator by adding a closing parentheses if and 637 * when necessary. Called during ascending phase of the 638 * parse tree walk. 639 * 640 ******************************************************************************/ 641 642 void 643 AcpiDmCloseOperator ( 644 ACPI_PARSE_OBJECT *Op) 645 { 646 BOOLEAN IsCStyleOp = FALSE; 647 648 649 /* Always emit paren if ASL+ disassembly disabled */ 650 651 if (!AcpiGbl_CstyleDisassembly) 652 { 653 AcpiOsPrintf (")"); 654 return; 655 } 656 657 /* Check for a non-ASL+ statement */ 658 659 if (Op->Common.DisasmFlags & ACPI_PARSEOP_LEGACY_ASL_ONLY) 660 { 661 AcpiOsPrintf (")"); 662 return; 663 } 664 665 /* Check if we need to add an additional closing paren */ 666 667 switch (Op->Common.AmlOpcode) 668 { 669 case AML_ADD_OP: 670 case AML_SUBTRACT_OP: 671 case AML_MULTIPLY_OP: 672 case AML_DIVIDE_OP: 673 case AML_MOD_OP: 674 case AML_SHIFT_LEFT_OP: 675 case AML_SHIFT_RIGHT_OP: 676 case AML_BIT_AND_OP: 677 case AML_BIT_OR_OP: 678 case AML_BIT_XOR_OP: 679 case AML_LAND_OP: 680 case AML_LEQUAL_OP: 681 case AML_LGREATER_OP: 682 case AML_LLESS_OP: 683 case AML_LOR_OP: 684 685 /* Emit paren only if this is not a compound assignment */ 686 687 if (Op->Common.DisasmFlags & ACPI_PARSEOP_COMPOUND_ASSIGNMENT) 688 { 689 return; 690 } 691 692 /* Emit extra close paren for assignment within an expression */ 693 694 if (Op->Common.DisasmFlags & ACPI_PARSEOP_ASSIGNMENT) 695 { 696 AcpiOsPrintf (")"); 697 } 698 699 IsCStyleOp = TRUE; 700 break; 701 702 case AML_INDEX_OP: 703 704 /* This is case for unsupported Index() source constants */ 705 706 if (Op->Common.DisasmFlags & ACPI_PARSEOP_CLOSING_PAREN) 707 { 708 AcpiOsPrintf (")"); 709 } 710 return; 711 712 /* No need for parens for these */ 713 714 case AML_DECREMENT_OP: 715 case AML_INCREMENT_OP: 716 case AML_LNOT_OP: 717 case AML_BIT_NOT_OP: 718 case AML_STORE_OP: 719 return; 720 721 default: 722 723 /* Always emit paren for non-ASL+ operators */ 724 break; 725 } 726 727 /* 728 * Nodes marked with ACPI_PARSEOP_PARAMLIST don't need a parens 729 * output here. We also need to check the parent to see if this op 730 * is part of a compound test (!=, >=, <=). 731 */ 732 if (IsCStyleOp && 733 ((Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) || 734 ((Op->Common.Parent->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST) && 735 (Op->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX)))) 736 { 737 return; 738 } 739 740 AcpiOsPrintf (")"); 741 return; 742 } 743 744 745 /******************************************************************************* 746 * 747 * FUNCTION: AcpiDmGetCompoundSymbol 748 * 749 * PARAMETERS: AslOpcode 750 * 751 * RETURN: String containing the compound assignment symbol 752 * 753 * DESCRIPTION: Detect opcodes that can be converted to compound assignment, 754 * return the appropriate operator string. 755 * 756 ******************************************************************************/ 757 758 static char * 759 AcpiDmGetCompoundSymbol ( 760 UINT16 AmlOpcode) 761 { 762 char *Symbol; 763 764 765 switch (AmlOpcode) 766 { 767 case AML_ADD_OP: 768 Symbol = " += "; 769 break; 770 771 case AML_SUBTRACT_OP: 772 Symbol = " -= "; 773 break; 774 775 case AML_MULTIPLY_OP: 776 Symbol = " *= "; 777 break; 778 779 case AML_DIVIDE_OP: 780 Symbol = " /= "; 781 break; 782 783 case AML_MOD_OP: 784 Symbol = " %= "; 785 break; 786 787 case AML_SHIFT_LEFT_OP: 788 Symbol = " <<= "; 789 break; 790 791 case AML_SHIFT_RIGHT_OP: 792 Symbol = " >>= "; 793 break; 794 795 case AML_BIT_AND_OP: 796 Symbol = " &= "; 797 break; 798 799 case AML_BIT_OR_OP: 800 Symbol = " |= "; 801 break; 802 803 case AML_BIT_XOR_OP: 804 Symbol = " ^= "; 805 break; 806 807 default: 808 809 /* No operator string for all other opcodes */ 810 811 return (NULL); 812 } 813 814 return (Symbol); 815 } 816 817 818 /******************************************************************************* 819 * 820 * FUNCTION: AcpiDmPromoteTarget 821 * 822 * PARAMETERS: Op - Operator parse object 823 * Target - Target associate with the Op 824 * 825 * RETURN: None 826 * 827 * DESCRIPTION: Transform the parse tree by moving the target up to the first 828 * child of the Op. 829 * 830 ******************************************************************************/ 831 832 static void 833 AcpiDmPromoteTarget ( 834 ACPI_PARSE_OBJECT *Op, 835 ACPI_PARSE_OBJECT *Target) 836 { 837 ACPI_PARSE_OBJECT *Child; 838 839 840 /* Link target directly to the Op as first child */ 841 842 Child = Op->Common.Value.Arg; 843 Op->Common.Value.Arg = Target; 844 Target->Common.Next = Child; 845 846 /* Find the last peer, it is linked to the target. Unlink it. */ 847 848 while (Child->Common.Next != Target) 849 { 850 Child = Child->Common.Next; 851 } 852 853 Child->Common.Next = NULL; 854 } 855 856 857 /******************************************************************************* 858 * 859 * FUNCTION: AcpiDmIsValidTarget 860 * 861 * PARAMETERS: Target - Target Op from the parse tree 862 * 863 * RETURN: TRUE if the Target is real. FALSE if it is just a placeholder 864 * Op that was inserted by the parser. 865 * 866 * DESCRIPTION: Determine if a Target Op is a placeholder Op or a real Target. 867 * In other words, determine if the optional target is used or 868 * not. Note: If Target is NULL, something is seriously wrong, 869 * probably with the parse tree. 870 * 871 ******************************************************************************/ 872 873 static BOOLEAN 874 AcpiDmIsValidTarget ( 875 ACPI_PARSE_OBJECT *Target) 876 { 877 878 if (!Target) 879 { 880 return (FALSE); 881 } 882 883 if ((Target->Common.AmlOpcode == AML_INT_NAMEPATH_OP) && 884 (Target->Common.Value.Arg == NULL)) 885 { 886 return (FALSE); 887 } 888 889 return (TRUE); 890 } 891 892 893 /******************************************************************************* 894 * 895 * FUNCTION: AcpiDmIsTargetAnOperand 896 * 897 * PARAMETERS: Target - Target associated with the expression 898 * Operand - An operand associated with expression 899 * 900 * RETURN: TRUE if expression can be converted to a compound assignment. 901 * FALSE otherwise. 902 * 903 * DESCRIPTION: Determine if the Target duplicates the operand, in order to 904 * detect if the expression can be converted to a compound 905 * assigment. (+=, *=, etc.) 906 * 907 ******************************************************************************/ 908 909 static BOOLEAN 910 AcpiDmIsTargetAnOperand ( 911 ACPI_PARSE_OBJECT *Target, 912 ACPI_PARSE_OBJECT *Operand, 913 BOOLEAN TopLevel) 914 { 915 const ACPI_OPCODE_INFO *OpInfo; 916 BOOLEAN Same; 917 918 919 /* 920 * Opcodes must match. Note: ignoring the difference between nameseg 921 * and namepath for now. May be needed later. 922 */ 923 if (Target->Common.AmlOpcode != Operand->Common.AmlOpcode) 924 { 925 return (FALSE); 926 } 927 928 /* Nodes should match, even if they are NULL */ 929 930 if (Target->Common.Node != Operand->Common.Node) 931 { 932 return (FALSE); 933 } 934 935 /* Determine if a child exists */ 936 937 OpInfo = AcpiPsGetOpcodeInfo (Operand->Common.AmlOpcode); 938 if (OpInfo->Flags & AML_HAS_ARGS) 939 { 940 Same = AcpiDmIsTargetAnOperand (Target->Common.Value.Arg, 941 Operand->Common.Value.Arg, FALSE); 942 if (!Same) 943 { 944 return (FALSE); 945 } 946 } 947 948 /* Check the next peer, as long as we are not at the top level */ 949 950 if ((!TopLevel) && 951 Target->Common.Next) 952 { 953 Same = AcpiDmIsTargetAnOperand (Target->Common.Next, 954 Operand->Common.Next, FALSE); 955 if (!Same) 956 { 957 return (FALSE); 958 } 959 } 960 961 /* Supress the duplicate operand at the top-level */ 962 963 if (TopLevel) 964 { 965 Operand->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 966 } 967 return (TRUE); 968 } 969