Merge branch 'vendor/BMAKE'
[dragonfly.git] / sys / contrib / dev / acpica / source / components / disassembler / dmcstyle.c
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 "acdisasm.h"
49 #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         /*
341          * Check for possible conversion to a "Compound Assignment".
342          *
343          * Determine if either operand is the same as the target
344          * and display compound assignment operator and other operand.
345          */
346         if ((AcpiDmIsTargetAnOperand (Target, Child1, TRUE)) ||
347             (AcpiDmIsTargetAnOperand (Target, Child2, TRUE)))
348         {
349             Target->Common.OperatorSymbol =
350                 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode);
351
352             /* Convert operator to compound assignment */
353
354             Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND;
355             Child1->Common.OperatorSymbol = NULL;
356             return (TRUE);
357         }
358
359         /*
360          * If we are within a C-style expression, emit an extra open
361          * paren. Implemented by examining the parent op.
362          */
363         switch (Op->Common.Parent->Common.AmlOpcode)
364         {
365         case AML_ADD_OP:
366         case AML_SUBTRACT_OP:
367         case AML_MULTIPLY_OP:
368         case AML_DIVIDE_OP:
369         case AML_MOD_OP:
370         case AML_SHIFT_LEFT_OP:
371         case AML_SHIFT_RIGHT_OP:
372         case AML_BIT_AND_OP:
373         case AML_BIT_OR_OP:
374         case AML_BIT_XOR_OP:
375         case AML_LAND_OP:
376         case AML_LEQUAL_OP:
377         case AML_LGREATER_OP:
378         case AML_LLESS_OP:
379         case AML_LOR_OP:
380
381             Op->Common.DisasmFlags |= ACPI_PARSEOP_ASSIGNMENT;
382             AcpiOsPrintf ("(");
383             break;
384
385         default:
386             break;
387         }
388
389         /* Normal output for ASL/AML operators with a target operand */
390
391         Target->Common.OperatorSymbol = " = (";
392         return (TRUE);
393
394     /* Binary operators, no parens */
395
396     case AML_DECREMENT_OP:
397     case AML_INCREMENT_OP:
398         return (TRUE);
399
400 #ifdef INDEX_SUPPORT
401     case AML_INDEX_OP:
402
403         /* Target is optional, 3rd operand */
404
405         Target = Child2->Common.Next;
406         if (AcpiDmIsValidTarget (Target))
407         {
408             AcpiDmPromoteTarget (Op, Target);
409
410             if (!Target->Common.OperatorSymbol)
411             {
412                 Target->Common.OperatorSymbol = " = ";
413             }
414         }
415         return (TRUE);
416 #endif
417
418     case AML_STORE_OP:
419         /*
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.
424          */
425         Target = Child1->Common.Next;
426         AcpiDmPromoteTarget (Op, Target);
427
428         if (!Target->Common.OperatorSymbol)
429         {
430             Target->Common.OperatorSymbol = " = ";
431         }
432         return (TRUE);
433
434     case AML_BIT_NOT_OP:
435
436         /* Target is optional, 2nd operand */
437
438         Target = Child1->Common.Next;
439         if (!Target)
440         {
441             return (FALSE);
442         }
443
444         if (AcpiDmIsValidTarget (Target))
445         {
446             /* Valid target, not a placeholder */
447
448             AcpiDmPromoteTarget (Op, Target);
449             Target->Common.OperatorSymbol = " = ~";
450         }
451         else
452         {
453             /* No target. Emit this prefix operator immediately */
454
455             AcpiOsPrintf ("~");
456         }
457         return (TRUE);
458
459     default:
460         break;
461     }
462
463     /* All other operators, emit an open paren */
464
465     AcpiOsPrintf ("(");
466     return (TRUE);
467 }
468
469
470 /*******************************************************************************
471  *
472  * FUNCTION:    AcpiDmCloseOperator
473  *
474  * PARAMETERS:  Op                  - Current parse object
475  *
476  * RETURN:      None
477  *
478  * DESCRIPTION: Closes an operator by adding a closing parentheses if and
479  *              when necessary. Called during ascending phase of the
480  *              parse tree walk.
481  *
482  ******************************************************************************/
483
484 void
485 AcpiDmCloseOperator (
486     ACPI_PARSE_OBJECT       *Op)
487 {
488
489     /* Always emit paren if ASL+ disassembly disabled */
490
491     if (!AcpiGbl_CstyleDisassembly)
492     {
493         AcpiOsPrintf (")");
494         return;
495     }
496
497     /* Check if we need to add an additional closing paren */
498
499     switch (Op->Common.AmlOpcode)
500     {
501     case AML_ADD_OP:
502     case AML_SUBTRACT_OP:
503     case AML_MULTIPLY_OP:
504     case AML_DIVIDE_OP:
505     case AML_MOD_OP:
506     case AML_SHIFT_LEFT_OP:
507     case AML_SHIFT_RIGHT_OP:
508     case AML_BIT_AND_OP:
509     case AML_BIT_OR_OP:
510     case AML_BIT_XOR_OP:
511     case AML_LAND_OP:
512     case AML_LEQUAL_OP:
513     case AML_LGREATER_OP:
514     case AML_LLESS_OP:
515     case AML_LOR_OP:
516
517         /* Emit paren only if this is not a compound assignment */
518
519         if (Op->Common.DisasmFlags & ACPI_PARSEOP_COMPOUND)
520         {
521             return;
522         }
523
524         /* Emit extra close paren for assignment within an expression */
525
526         if (Op->Common.DisasmFlags & ACPI_PARSEOP_ASSIGNMENT)
527         {
528             AcpiOsPrintf (")");
529         }
530         break;
531
532
533     /* No need for parens for these */
534
535 #ifdef INDEX_SUPPORT
536     case AML_INDEX_OP:
537 #endif
538     case AML_DECREMENT_OP:
539     case AML_INCREMENT_OP:
540     case AML_LNOT_OP:
541     case AML_BIT_NOT_OP:
542     case AML_STORE_OP:
543         return;
544
545     default:
546
547         /* Always emit paren for non-ASL+ operators */
548         break;
549     }
550
551     AcpiOsPrintf (")");
552 }
553
554
555 /*******************************************************************************
556  *
557  * FUNCTION:    AcpiDmGetCompoundSymbol
558  *
559  * PARAMETERS:  AslOpcode
560  *
561  * RETURN:      String containing the compound assignment symbol
562  *
563  * DESCRIPTION: Detect opcodes that can be converted to compound assignment,
564  *              return the appropriate operator string.
565  *
566  ******************************************************************************/
567
568 static char *
569 AcpiDmGetCompoundSymbol (
570    UINT16                   AmlOpcode)
571 {
572     char                    *Symbol;
573
574
575     switch (AmlOpcode)
576     {
577     case AML_ADD_OP:
578         Symbol = " += ";
579         break;
580
581     case AML_SUBTRACT_OP:
582         Symbol = " -= ";
583         break;
584
585     case AML_MULTIPLY_OP:
586         Symbol = " *= ";
587         break;
588
589     case AML_DIVIDE_OP:
590         Symbol = " /= ";
591         break;
592
593     case AML_MOD_OP:
594         Symbol = " %= ";
595         break;
596
597     case AML_SHIFT_LEFT_OP:
598         Symbol = " <<= ";
599         break;
600
601     case AML_SHIFT_RIGHT_OP:
602         Symbol = " >>= ";
603         break;
604
605     case AML_BIT_AND_OP:
606         Symbol = " &= ";
607         break;
608
609     case AML_BIT_OR_OP:
610         Symbol = " |= ";
611         break;
612
613     case AML_BIT_XOR_OP:
614         Symbol = " ^= ";
615         break;
616
617     default:
618
619         /* No operator string for all other opcodes */
620         return (NULL);
621     }
622
623     return (Symbol);
624 }
625
626
627 /*******************************************************************************
628  *
629  * FUNCTION:    AcpiDmPromoteTarget
630  *
631  * PARAMETERS:  Op                  - Operator parse object
632  *              Target              - Target associate with the Op
633  *
634  * RETURN:      None
635  *
636  * DESCRIPTION: Transform the parse tree by moving the target up to the first
637  *              child of the Op.
638  *
639  ******************************************************************************/
640
641 static void
642 AcpiDmPromoteTarget (
643     ACPI_PARSE_OBJECT       *Op,
644     ACPI_PARSE_OBJECT       *Target)
645 {
646     ACPI_PARSE_OBJECT       *Child;
647
648
649     /* Link target directly to the Op as first child */
650
651     Child = Op->Common.Value.Arg;
652     Op->Common.Value.Arg = Target;
653     Target->Common.Next = Child;
654
655     /* Find the last peer, it is linked to the target. Unlink it. */
656
657     while (Child->Common.Next != Target)
658     {
659         Child = Child->Common.Next;
660     }
661
662     Child->Common.Next = NULL;
663 }
664
665
666 /*******************************************************************************
667  *
668  * FUNCTION:    AcpiDmIsValidTarget
669  *
670  * PARAMETERS:  Target              - Target Op from the parse tree
671  *
672  * RETURN:      TRUE if the Target is real. FALSE if it is just a placeholder
673  *              Op that was inserted by the parser.
674  *
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
677  *              not.
678  *
679  ******************************************************************************/
680
681 static BOOLEAN
682 AcpiDmIsValidTarget (
683     ACPI_PARSE_OBJECT       *Target)
684 {
685
686     if ((Target->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
687         (Target->Common.Value.Arg == NULL))
688     {
689         return (FALSE);
690     }
691
692     return (TRUE);
693 }
694
695
696 /*******************************************************************************
697  *
698  * FUNCTION:    AcpiDmIsTargetAnOperand
699  *
700  * PARAMETERS:  Target              - Target associated with the expression
701  *              Operand             - An operand associated with expression
702  *
703  * RETURN:      TRUE if expression can be converted to a compound assignment.
704  *              FALSE otherwise.
705  *
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.)
709  *
710  ******************************************************************************/
711
712 static BOOLEAN
713 AcpiDmIsTargetAnOperand (
714     ACPI_PARSE_OBJECT       *Target,
715     ACPI_PARSE_OBJECT       *Operand,
716     BOOLEAN                 TopLevel)
717 {
718     const ACPI_OPCODE_INFO  *OpInfo;
719     BOOLEAN                 Same;
720
721
722     /*
723      * Opcodes must match. Note: ignoring the difference between nameseg
724      * and namepath for now. May be needed later.
725      */
726     if (Target->Common.AmlOpcode != Operand->Common.AmlOpcode)
727     {
728         return (FALSE);
729     }
730
731     /* Nodes should match, even if they are NULL */
732
733     if (Target->Common.Node != Operand->Common.Node)
734     {
735         return (FALSE);
736     }
737
738     /* Determine if a child exists */
739
740     OpInfo = AcpiPsGetOpcodeInfo (Operand->Common.AmlOpcode);
741     if (OpInfo->Flags & AML_HAS_ARGS)
742     {
743         Same = AcpiDmIsTargetAnOperand (Target->Common.Value.Arg,
744             Operand->Common.Value.Arg, FALSE);
745         if (!Same)
746         {
747             return (FALSE);
748         }
749     }
750
751     /* Check the next peer, as long as we are not at the top level */
752
753     if ((!TopLevel) &&
754          Target->Common.Next)
755     {
756         Same = AcpiDmIsTargetAnOperand (Target->Common.Next,
757             Operand->Common.Next, FALSE);
758         if (!Same)
759         {
760             return (FALSE);
761         }
762     }
763
764     /* Supress the duplicate operand at the top-level */
765
766     if (TopLevel)
767     {
768         Operand->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
769     }
770     return (TRUE);
771 }
772
773 #endif