1 /******************************************************************************
2  *
3  * Module Name: asldebug -- Debug output support
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2022, 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 MERCHANTABILITY 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 
47 
48 #define _COMPONENT          ACPI_COMPILER
49         ACPI_MODULE_NAME    ("asldebug")
50 
51 
52 /* Local prototypes */
53 
54 static void
55 UtDumpParseOpName (
56     ACPI_PARSE_OBJECT       *Op,
57     UINT32                  Level,
58     UINT32                  DataLength);
59 
60 static char *
61 UtCreateEscapeSequences (
62     char                    *InString);
63 
64 
65 /*******************************************************************************
66  *
67  * FUNCTION:    CvDbgPrint
68  *
69  * PARAMETERS:  Type                - Type of output
70  *              Fmt                 - Printf format string
71  *              ...                 - variable printf list
72  *
73  * RETURN:      None
74  *
75  * DESCRIPTION: Print statement for debug messages within the converter.
76  *
77  ******************************************************************************/
78 
79 void
CvDbgPrint(char * Fmt,...)80 CvDbgPrint (
81     char                    *Fmt,
82     ...)
83 {
84     va_list                 Args;
85 
86 
87     if (!AcpiGbl_CaptureComments || !AcpiGbl_DebugAslConversion)
88     {
89         return;
90     }
91 
92     va_start (Args, Fmt);
93     (void) vfprintf (AcpiGbl_ConvDebugFile, Fmt, Args);
94     va_end (Args);
95     return;
96 }
97 
98 
99 /*******************************************************************************
100  *
101  * FUNCTION:    UtDumpIntegerOp
102  *
103  * PARAMETERS:  Op                  - Current parse op
104  *              Level               - Current output indentation level
105  *              IntegerLength       - Output length of the integer (2/4/8/16)
106  *
107  * RETURN:      None
108  *
109  * DESCRIPTION: Emit formatted debug output for "integer" ops.
110  *              Note: IntegerLength must be one of 2,4,8,16.
111  *
112  ******************************************************************************/
113 
114 void
UtDumpIntegerOp(ACPI_PARSE_OBJECT * Op,UINT32 Level,UINT32 IntegerLength)115 UtDumpIntegerOp (
116     ACPI_PARSE_OBJECT       *Op,
117     UINT32                  Level,
118     UINT32                  IntegerLength)
119 {
120 
121     /* Emit the ParseOp name, leaving room for the integer */
122 
123     UtDumpParseOpName (Op, Level, IntegerLength);
124 
125     /* Emit the integer based upon length */
126 
127     switch (IntegerLength)
128     {
129     case 2: /* Byte */
130     case 4: /* Word */
131     case 8: /* Dword */
132 
133         DbgPrint (ASL_TREE_OUTPUT,
134             "%*.*X", IntegerLength, IntegerLength, (UINT32) Op->Asl.Value.Integer);
135         break;
136 
137     case 16: /* Qword and Integer */
138 
139         DbgPrint (ASL_TREE_OUTPUT,
140             "%8.8X%8.8X", ACPI_FORMAT_UINT64 (Op->Asl.Value.Integer));
141         break;
142 
143     default:
144         break;
145     }
146 }
147 
148 
149 /*******************************************************************************
150  *
151  * FUNCTION:    UtDumpStringOp
152  *
153  * PARAMETERS:  Op                  - Current parse op
154  *              Level               - Current output indentation level
155  *
156  * RETURN:      None
157  *
158  * DESCRIPTION: Emit formatted debug output for String/Pathname ops.
159  *
160  ******************************************************************************/
161 
162 void
UtDumpStringOp(ACPI_PARSE_OBJECT * Op,UINT32 Level)163 UtDumpStringOp (
164     ACPI_PARSE_OBJECT       *Op,
165     UINT32                  Level)
166 {
167     char                    *String;
168 
169 
170     String = Op->Asl.Value.String;
171     if (Op->Asl.ParseOpcode != PARSEOP_STRING_LITERAL)
172     {
173         /*
174          * For the "path" ops NAMEPATH, NAMESEG, METHODCALL -- if the
175          * ExternalName is valid, it takes precedence. In these cases the
176          * Value.String is the raw "internal" name from the AML code, which
177          * we don't want to use, because it contains non-ascii characters.
178          */
179         if (Op->Asl.ExternalName)
180         {
181             String = Op->Asl.ExternalName;
182         }
183     }
184 
185     if (!String)
186     {
187         DbgPrint (ASL_TREE_OUTPUT,
188             " ERROR: Could not find a valid String/Path pointer\n");
189         return;
190     }
191 
192     String = UtCreateEscapeSequences (String);
193 
194     /* Emit the ParseOp name, leaving room for the string */
195 
196     UtDumpParseOpName (Op, Level, strlen (String));
197     DbgPrint (ASL_TREE_OUTPUT, "%s", String);
198 }
199 
200 
201 /*******************************************************************************
202  *
203  * FUNCTION:    UtCreateEscapeSequences
204  *
205  * PARAMETERS:  InString            - ASCII string to be expanded
206  *
207  * RETURN:      Expanded string
208  *
209  * DESCRIPTION: Expand all non-printable ASCII bytes (0-0x1F) to escape
210  *              sequences. For example, hex 14 becomes \x14
211  *
212  * NOTE:        Since this function is used for debug output only, it does
213  *              not attempt to translate into the "known" escape sequences
214  *              such as \a, \f, \t, etc.
215  *
216  ******************************************************************************/
217 
218 static char *
UtCreateEscapeSequences(char * InString)219 UtCreateEscapeSequences (
220     char                    *InString)
221 {
222     char                    *String = InString;
223     char                    *OutString;
224     char                    *OutStringPtr;
225     UINT32                  InStringLength = 0;
226     UINT32                  EscapeCount = 0;
227 
228 
229     /*
230      * Determine up front how many escapes are within the string.
231      * Obtain the input string length while doing so.
232      */
233     while (*String)
234     {
235         if ((*String <= 0x1F) || (*String >= 0x7F))
236         {
237             EscapeCount++;
238         }
239 
240         InStringLength++;
241         String++;
242     }
243 
244     if (!EscapeCount)
245     {
246         return (InString); /* No escapes, nothing to do */
247     }
248 
249     /* New string buffer, 3 extra chars per escape (4 total) */
250 
251     OutString = UtLocalCacheCalloc (InStringLength + (EscapeCount * 3));
252     OutStringPtr = OutString;
253 
254     /* Convert non-ascii or non-printable chars to escape sequences */
255 
256     while (*InString)
257     {
258         if ((*InString <= 0x1F) || (*InString >= 0x7F))
259         {
260             /* Insert a \x hex escape sequence */
261 
262             OutStringPtr[0] = '\\';
263             OutStringPtr[1] = 'x';
264             OutStringPtr[2] = AcpiUtHexToAsciiChar (*InString, 4);
265             OutStringPtr[3] = AcpiUtHexToAsciiChar (*InString, 0);
266             OutStringPtr += 4;
267         }
268         else /* Normal ASCII character */
269         {
270             *OutStringPtr = *InString;
271             OutStringPtr++;
272         }
273 
274         InString++;
275     }
276 
277     return (OutString);
278 }
279 
280 
281 /*******************************************************************************
282  *
283  * FUNCTION:    UtDumpBasicOp
284  *
285  * PARAMETERS:  Op                  - Current parse op
286  *              Level               - Current output indentation level
287  *
288  * RETURN:      None
289  *
290  * DESCRIPTION: Generic formatted debug output for "basic" ops that have no
291  *              associated strings or integer values.
292  *
293  ******************************************************************************/
294 
295 void
UtDumpBasicOp(ACPI_PARSE_OBJECT * Op,UINT32 Level)296 UtDumpBasicOp (
297     ACPI_PARSE_OBJECT       *Op,
298     UINT32                  Level)
299 {
300 
301     /* Just print out the ParseOp name, there is no extra data */
302 
303     UtDumpParseOpName (Op, Level, 0);
304 }
305 
306 
307 /*******************************************************************************
308  *
309  * FUNCTION:    UtDumpParseOpName
310  *
311  * PARAMETERS:  Op                  - Current parse op
312  *              Level               - Current output indentation level
313  *              DataLength          - Length of data to appear after the name
314  *
315  * RETURN:      None
316  *
317  * DESCRIPTION: Indent and emit the ascii ParseOp name for the op
318  *
319  ******************************************************************************/
320 
321 static void
UtDumpParseOpName(ACPI_PARSE_OBJECT * Op,UINT32 Level,UINT32 DataLength)322 UtDumpParseOpName (
323     ACPI_PARSE_OBJECT       *Op,
324     UINT32                  Level,
325     UINT32                  DataLength)
326 {
327     char                    *ParseOpName;
328     UINT32                  IndentLength;
329     UINT32                  NameLength;
330     UINT32                  LineLength;
331     UINT32                  PaddingLength;
332 
333 
334     /* Emit the LineNumber/IndentLevel prefix on each output line */
335 
336     DbgPrint (ASL_TREE_OUTPUT,
337         "%5.5d [%2d]", Op->Asl.LogicalLineNumber, Level);
338 
339     ParseOpName = UtGetOpName (Op->Asl.ParseOpcode);
340 
341     /* Calculate various lengths for output alignment */
342 
343     IndentLength = Level * DEBUG_SPACES_PER_INDENT;
344     NameLength = strlen (ParseOpName);
345     LineLength = IndentLength + 1 + NameLength + 1 + DataLength;
346     PaddingLength = (DEBUG_MAX_LINE_LENGTH + 1) - LineLength;
347 
348     /* Parse tree indentation is based upon the nesting/indent level */
349 
350     if (Level)
351     {
352         DbgPrint (ASL_TREE_OUTPUT, "%*s", IndentLength, " ");
353     }
354 
355     /* Emit the actual name here */
356 
357     DbgPrint (ASL_TREE_OUTPUT, " %s", ParseOpName);
358 
359     /* Emit extra padding blanks for alignment of later data items */
360 
361     if (LineLength > DEBUG_MAX_LINE_LENGTH)
362     {
363         /* Split a long line immediately after the ParseOpName string */
364 
365         DbgPrint (ASL_TREE_OUTPUT, "\n%*s",
366             (DEBUG_FULL_LINE_LENGTH - DataLength), " ");
367     }
368     else
369     {
370         DbgPrint (ASL_TREE_OUTPUT, "%*s", PaddingLength, " ");
371     }
372 }
373