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