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