Home | History | Annotate | Line # | Download | only in compiler
aslprintf.c revision 1.1.1.9
      1 /******************************************************************************
      2  *
      3  * Module Name: aslprintf - ASL Printf/Fprintf macro support
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2019, 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 "aslcompiler.h"
     45 #include "aslcompiler.y.h"
     46 #include "amlcode.h"
     47 
     48 #define _COMPONENT          ACPI_COMPILER
     49         ACPI_MODULE_NAME    ("aslprintf")
     50 
     51 
     52 /* Local prototypes */
     53 
     54 static void
     55 OpcCreateConcatenateNode (
     56     ACPI_PARSE_OBJECT       *Op,
     57     ACPI_PARSE_OBJECT       *Node);
     58 
     59 static void
     60 OpcParsePrintf (
     61     ACPI_PARSE_OBJECT       *Op,
     62     ACPI_PARSE_OBJECT       *DestOp);
     63 
     64 
     65 /*******************************************************************************
     66  *
     67  * FUNCTION:    OpcDoPrintf
     68  *
     69  * PARAMETERS:  Op                  - printf parse node
     70  *
     71  * RETURN:      None
     72  *
     73  * DESCRIPTION: Convert printf macro to a Store(..., Debug) AML operation.
     74  *
     75  ******************************************************************************/
     76 
     77 void
     78 OpcDoPrintf (
     79     ACPI_PARSE_OBJECT       *Op)
     80 {
     81     ACPI_PARSE_OBJECT       *DestOp;
     82 
     83 
     84     /* Store destination is the Debug op */
     85 
     86     DestOp = TrAllocateOp (PARSEOP_DEBUG);
     87     DestOp->Asl.AmlOpcode = AML_DEBUG_OP;
     88     DestOp->Asl.Parent = Op;
     89     DestOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber;
     90 
     91     OpcParsePrintf (Op, DestOp);
     92 }
     93 
     94 
     95 /*******************************************************************************
     96  *
     97  * FUNCTION:    OpcDoFprintf
     98  *
     99  * PARAMETERS:  Op                  - fprintf parse node
    100  *
    101  * RETURN:      None
    102  *
    103  * DESCRIPTION: Convert fprintf macro to a Store AML operation.
    104  *
    105  ******************************************************************************/
    106 
    107 void
    108 OpcDoFprintf (
    109     ACPI_PARSE_OBJECT       *Op)
    110 {
    111     ACPI_PARSE_OBJECT       *DestOp;
    112 
    113 
    114     /* Store destination is the first argument of fprintf */
    115 
    116     DestOp = Op->Asl.Child;
    117     Op->Asl.Child = DestOp->Asl.Next;
    118     DestOp->Asl.Next = NULL;
    119 
    120     OpcParsePrintf (Op, DestOp);
    121 }
    122 
    123 
    124 /*******************************************************************************
    125  *
    126  * FUNCTION:    OpcParsePrintf
    127  *
    128  * PARAMETERS:  Op                  - Printf parse node
    129  *              DestOp              - Destination of Store operation
    130  *
    131  * RETURN:      None
    132  *
    133  * DESCRIPTION: Convert printf macro to a Store AML operation. The printf
    134  *              macro parse tree is laid out as follows:
    135  *
    136  *              Op        - printf parse op
    137  *              Op->Child - Format string
    138  *              Op->Next  - Format string arguments
    139  *
    140  ******************************************************************************/
    141 
    142 static void
    143 OpcParsePrintf (
    144     ACPI_PARSE_OBJECT       *Op,
    145     ACPI_PARSE_OBJECT       *DestOp)
    146 {
    147     char                    *Format;
    148     char                    *StartPosition = NULL;
    149     ACPI_PARSE_OBJECT       *ArgNode;
    150     ACPI_PARSE_OBJECT       *NextNode;
    151     UINT32                  StringLength = 0;
    152     char                    *NewString;
    153     BOOLEAN                 StringToProcess = FALSE;
    154     ACPI_PARSE_OBJECT       *NewOp;
    155 
    156 
    157     /* Get format string */
    158 
    159     Format = ACPI_CAST_PTR (char, Op->Asl.Child->Asl.Value.String);
    160     ArgNode = Op->Asl.Child->Asl.Next;
    161 
    162     /*
    163      * Detach argument list so that we can use a NULL check to distinguish
    164      * the first concatenation operation we need to make
    165      */
    166     Op->Asl.Child = NULL;
    167 
    168     for (; *Format; ++Format)
    169     {
    170         if (*Format != '%')
    171         {
    172             if (!StringToProcess)
    173             {
    174                 /* Mark the beginning of a string */
    175 
    176                 StartPosition = Format;
    177                 StringToProcess = TRUE;
    178             }
    179 
    180             ++StringLength;
    181             continue;
    182         }
    183 
    184         /* Save string, if any, to new string object and concat it */
    185 
    186         if (StringToProcess)
    187         {
    188             NewString = UtLocalCacheCalloc (StringLength + 1);
    189             strncpy (NewString, StartPosition, StringLength);
    190 
    191             NewOp = TrAllocateOp (PARSEOP_STRING_LITERAL);
    192             NewOp->Asl.Value.String = NewString;
    193             NewOp->Asl.AmlOpcode = AML_STRING_OP;
    194             NewOp->Asl.AcpiBtype = ACPI_BTYPE_STRING;
    195             NewOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber;
    196 
    197             OpcCreateConcatenateNode(Op, NewOp);
    198 
    199             StringLength = 0;
    200             StringToProcess = FALSE;
    201         }
    202 
    203         ++Format;
    204 
    205         /*
    206          * We have a format parameter and will need an argument to go
    207          * with it
    208          */
    209         if (!ArgNode ||
    210             ArgNode->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)
    211         {
    212             AslError(ASL_ERROR, ASL_MSG_ARG_COUNT_LO, Op, NULL);
    213             return;
    214         }
    215 
    216         /*
    217          * We do not support sub-specifiers of printf (flags, width,
    218          * precision, length). For specifiers we only support %x/%X for
    219          * hex or %s for strings. Also, %o for generic "acpi object".
    220          */
    221         switch (*Format)
    222         {
    223         case 's':
    224 
    225             if (ArgNode->Asl.ParseOpcode != PARSEOP_STRING_LITERAL)
    226             {
    227                 AslError(ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgNode,
    228                     "String required");
    229                 return;
    230             }
    231 
    232             NextNode = ArgNode->Asl.Next;
    233             ArgNode->Asl.Next = NULL;
    234             OpcCreateConcatenateNode(Op, ArgNode);
    235             ArgNode = NextNode;
    236             continue;
    237 
    238         case 'X':
    239         case 'x':
    240         case 'o':
    241 
    242             NextNode = ArgNode->Asl.Next;
    243             ArgNode->Asl.Next = NULL;
    244 
    245             /*
    246              * Append an empty string if the first argument is
    247              * not a string. This will implicitly conver the 2nd
    248              * concat source to a string per the ACPI specification.
    249              */
    250             if (!Op->Asl.Child)
    251             {
    252                 NewOp = TrAllocateOp (PARSEOP_STRING_LITERAL);
    253                 NewOp->Asl.Value.String = "";
    254                 NewOp->Asl.AmlOpcode = AML_STRING_OP;
    255                 NewOp->Asl.AcpiBtype = ACPI_BTYPE_STRING;
    256                 NewOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber;
    257 
    258                 OpcCreateConcatenateNode(Op, NewOp);
    259             }
    260 
    261             OpcCreateConcatenateNode(Op, ArgNode);
    262             ArgNode = NextNode;
    263             break;
    264 
    265         default:
    266 
    267             AslError(ASL_ERROR, ASL_MSG_INVALID_OPERAND, Op,
    268                 "Unrecognized format specifier");
    269             continue;
    270         }
    271     }
    272 
    273     /* Process any remaining string */
    274 
    275     if (StringToProcess)
    276     {
    277         NewString = UtLocalCacheCalloc (StringLength + 1);
    278         strncpy (NewString, StartPosition, StringLength);
    279 
    280         NewOp = TrAllocateOp (PARSEOP_STRING_LITERAL);
    281         NewOp->Asl.Value.String = NewString;
    282         NewOp->Asl.AcpiBtype = ACPI_BTYPE_STRING;
    283         NewOp->Asl.AmlOpcode = AML_STRING_OP;
    284         NewOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber;
    285 
    286         OpcCreateConcatenateNode(Op, NewOp);
    287     }
    288 
    289     /*
    290      * If we get here and there's no child node then Format
    291      * was an empty string. Just make a no op.
    292      */
    293     if (!Op->Asl.Child)
    294     {
    295         Op->Asl.ParseOpcode = PARSEOP_NOOP;
    296         AslError(ASL_WARNING, ASL_MSG_NULL_STRING, Op,
    297             "Converted to NOOP");
    298         return;
    299     }
    300 
    301      /* Check for erroneous extra arguments */
    302 
    303     if (ArgNode &&
    304         ArgNode->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)
    305     {
    306         AslError(ASL_WARNING, ASL_MSG_ARG_COUNT_HI, ArgNode,
    307             "Extra arguments ignored");
    308     }
    309 
    310     /* Change Op to a Store */
    311 
    312     Op->Asl.ParseOpcode = PARSEOP_STORE;
    313     Op->Common.AmlOpcode = AML_STORE_OP;
    314     Op->Asl.CompileFlags  = 0;
    315 
    316     /* Disable further optimization */
    317 
    318     Op->Asl.CompileFlags &= ~OP_COMPILE_TIME_CONST;
    319     UtSetParseOpName (Op);
    320 
    321     /* Set Store destination */
    322 
    323     Op->Asl.Child->Asl.Next = DestOp;
    324 }
    325 
    326 
    327 /*******************************************************************************
    328  *
    329  * FUNCTION:    OpcCreateConcatenateNode
    330  *
    331  * PARAMETERS:  Op                  - Parse node
    332  *              Node                - Parse node to be concatenated
    333  *
    334  * RETURN:      None
    335  *
    336  * DESCRIPTION: Make Node the child of Op. If child node already exists, then
    337  *              concat child with Node and makes concat node the child of Op.
    338  *
    339  ******************************************************************************/
    340 
    341 static void
    342 OpcCreateConcatenateNode (
    343     ACPI_PARSE_OBJECT       *Op,
    344     ACPI_PARSE_OBJECT       *Node)
    345 {
    346     ACPI_PARSE_OBJECT       *NewConcatOp;
    347 
    348 
    349     if (!Op->Asl.Child)
    350     {
    351         Op->Asl.Child = Node;
    352         Node->Asl.Parent = Op;
    353         return;
    354     }
    355 
    356     NewConcatOp = TrAllocateOp (PARSEOP_CONCATENATE);
    357     NewConcatOp->Asl.AmlOpcode = AML_CONCATENATE_OP;
    358     NewConcatOp->Asl.AcpiBtype = 0x7;
    359     NewConcatOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber;
    360 
    361     /* First arg is child of Op*/
    362 
    363     NewConcatOp->Asl.Child = Op->Asl.Child;
    364     Op->Asl.Child->Asl.Parent = NewConcatOp;
    365 
    366     /* Second arg is Node */
    367 
    368     NewConcatOp->Asl.Child->Asl.Next = Node;
    369     Node->Asl.Parent = NewConcatOp;
    370 
    371     /* Third arg is Zero (not used) */
    372 
    373     NewConcatOp->Asl.Child->Asl.Next->Asl.Next =
    374         TrAllocateOp (PARSEOP_ZERO);
    375     NewConcatOp->Asl.Child->Asl.Next->Asl.Next->Asl.Parent =
    376         NewConcatOp;
    377 
    378     Op->Asl.Child = NewConcatOp;
    379     NewConcatOp->Asl.Parent = Op;
    380 }
    381