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