1 /******************************************************************************
2  *
3  * Module Name: asllistsup - Listing file support utilities
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, 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 
47 
48 #define _COMPONENT          ACPI_COMPILER
49         ACPI_MODULE_NAME    ("aslistsup")
50 
51 
52 /*******************************************************************************
53  *
54  * FUNCTION:    LsDumpAscii
55  *
56  * PARAMETERS:  FileId          - ID of current listing file
57  *              Count           - Number of bytes to convert
58  *              Buffer          - Buffer of bytes to convert
59  *
60  * RETURN:      None
61  *
62  * DESCRIPTION: Convert hex bytes to ascii
63  *
64  ******************************************************************************/
65 
66 void
67 LsDumpAscii (
68     UINT32                  FileId,
69     UINT32                  Count,
70     UINT8                   *Buffer)
71 {
72     UINT8                   BufChar;
73     UINT32                  i;
74 
75 
76     FlPrintFile (FileId, "    \"");
77     for (i = 0; i < Count; i++)
78     {
79         BufChar = Buffer[i];
80         if (isprint (BufChar))
81         {
82             FlPrintFile (FileId, "%c", BufChar);
83         }
84         else
85         {
86             /* Not a printable character, just put out a dot */
87 
88             FlPrintFile (FileId, ".");
89         }
90     }
91 
92     FlPrintFile (FileId, "\"");
93 }
94 
95 
96 /*******************************************************************************
97  *
98  * FUNCTION:    LsDumpAsciiInComment
99  *
100  * PARAMETERS:  FileId          - ID of current listing file
101  *              Count           - Number of bytes to convert
102  *              Buffer          - Buffer of bytes to convert
103  *
104  * RETURN:      None
105  *
106  * DESCRIPTION: Convert hex bytes to ascii
107  *
108  ******************************************************************************/
109 
110 void
111 LsDumpAsciiInComment (
112     UINT32                  FileId,
113     UINT32                  Count,
114     UINT8                   *Buffer)
115 {
116     UINT8                   BufChar = 0;
117     UINT8                   LastChar;
118     UINT32                  i;
119 
120 
121     FlPrintFile (FileId, "    \"");
122     for (i = 0; i < Count; i++)
123     {
124         LastChar = BufChar;
125         BufChar = Buffer[i];
126 
127         if (isprint (BufChar))
128         {
129             /* Handle embedded C comment sequences */
130 
131             if (((LastChar == '*') && (BufChar == '/')) ||
132                 ((LastChar == '/') && (BufChar == '*')))
133             {
134                 /* Insert a space to break the sequence */
135 
136                 FlPrintFile (FileId, ".", BufChar);
137             }
138 
139             FlPrintFile (FileId, "%c", BufChar);
140         }
141         else
142         {
143             /* Not a printable character, just put out a dot */
144 
145             FlPrintFile (FileId, ".");
146         }
147     }
148 
149     FlPrintFile (FileId, "\"");
150 }
151 
152 
153 /*******************************************************************************
154  *
155  * FUNCTION:    LsCheckException
156  *
157  * PARAMETERS:  LineNumber          - Current logical (cumulative) line #
158  *              FileId              - ID of output listing file
159  *
160  * RETURN:      None
161  *
162  * DESCRIPTION: Check if there is an exception for this line, and if there is,
163  *              put it in the listing immediately. Handles multiple errors
164  *              per line. Gbl_NextError points to the next error in the
165  *              sorted (by line #) list of compile errors/warnings.
166  *
167  ******************************************************************************/
168 
169 void
170 LsCheckException (
171     UINT32                  LineNumber,
172     UINT32                  FileId)
173 {
174 
175     if ((!Gbl_NextError) ||
176         (LineNumber < Gbl_NextError->LogicalLineNumber ))
177     {
178         return;
179     }
180 
181     /* Handle multiple errors per line */
182 
183     if (FileId == ASL_FILE_LISTING_OUTPUT)
184     {
185         while (Gbl_NextError &&
186               (LineNumber >= Gbl_NextError->LogicalLineNumber))
187         {
188             AePrintException (FileId, Gbl_NextError, "\n[****iasl****]\n");
189             Gbl_NextError = Gbl_NextError->Next;
190         }
191 
192         FlPrintFile (FileId, "\n");
193     }
194 }
195 
196 
197 /*******************************************************************************
198  *
199  * FUNCTION:    LsWriteListingHexBytes
200  *
201  * PARAMETERS:  Buffer          - AML code buffer
202  *              Length          - Number of AML bytes to write
203  *              FileId          - ID of current listing file.
204  *
205  * RETURN:      None
206  *
207  * DESCRIPTION: Write the contents of the AML buffer to the listing file via
208  *              the listing buffer. The listing buffer is flushed every 16
209  *              AML bytes.
210  *
211  ******************************************************************************/
212 
213 void
214 LsWriteListingHexBytes (
215     UINT8                   *Buffer,
216     UINT32                  Length,
217     UINT32                  FileId)
218 {
219     UINT32                  i;
220 
221 
222     /* Transfer all requested bytes */
223 
224     for (i = 0; i < Length; i++)
225     {
226         /* Print line header when buffer is empty */
227 
228         if (Gbl_CurrentHexColumn == 0)
229         {
230             if (Gbl_HasIncludeFiles)
231             {
232                 FlPrintFile (FileId, "%*s", 10, " ");
233             }
234 
235             switch (FileId)
236             {
237             case ASL_FILE_LISTING_OUTPUT:
238 
239                 FlPrintFile (FileId, "%8.8X%s", Gbl_CurrentAmlOffset,
240                     ASL_LISTING_LINE_PREFIX);
241                 break;
242 
243             case ASL_FILE_ASM_SOURCE_OUTPUT:
244 
245                 FlPrintFile (FileId, "    db ");
246                 break;
247 
248             case ASL_FILE_C_SOURCE_OUTPUT:
249 
250                 FlPrintFile (FileId, "        ");
251                 break;
252 
253             default:
254 
255                 /* No other types supported */
256 
257                 return;
258             }
259         }
260 
261         /* Transfer AML byte and update counts */
262 
263         Gbl_AmlBuffer[Gbl_CurrentHexColumn] = Buffer[i];
264 
265         Gbl_CurrentHexColumn++;
266         Gbl_CurrentAmlOffset++;
267 
268         /* Flush buffer when it is full */
269 
270         if (Gbl_CurrentHexColumn >= HEX_LISTING_LINE_SIZE)
271         {
272             LsFlushListingBuffer (FileId);
273         }
274     }
275 }
276 
277 
278 /*******************************************************************************
279  *
280  * FUNCTION:    LsWriteSourceLines
281  *
282  * PARAMETERS:  ToLineNumber            -
283  *              ToLogicalLineNumber     - Write up to this source line number
284  *              FileId                  - ID of current listing file
285  *
286  * RETURN:      None
287  *
288  * DESCRIPTION: Read then write source lines to the listing file until we have
289  *              reached the specified logical (cumulative) line number. This
290  *              automatically echos out comment blocks and other non-AML
291  *              generating text until we get to the actual AML-generating line
292  *              of ASL code specified by the logical line number.
293  *
294  ******************************************************************************/
295 
296 void
297 LsWriteSourceLines (
298     UINT32                  ToLineNumber,
299     UINT32                  ToLogicalLineNumber,
300     UINT32                  FileId)
301 {
302 
303     /* Nothing to do for these file types */
304 
305     if ((FileId == ASL_FILE_ASM_INCLUDE_OUTPUT) ||
306         (FileId == ASL_FILE_C_INCLUDE_OUTPUT))
307     {
308         return;
309     }
310 
311     Gbl_CurrentLine = ToLogicalLineNumber;
312 
313     /* Flush any hex bytes remaining from the last opcode */
314 
315     LsFlushListingBuffer (FileId);
316 
317     /* Read lines and write them as long as we are not caught up */
318 
319     if (Gbl_SourceLine < Gbl_CurrentLine)
320     {
321         /*
322          * If we just completed writing some AML hex bytes, output a linefeed
323          * to add some whitespace for readability.
324          */
325         if (Gbl_HexBytesWereWritten)
326         {
327             FlPrintFile (FileId, "\n");
328             Gbl_HexBytesWereWritten = FALSE;
329         }
330 
331         if (FileId == ASL_FILE_C_SOURCE_OUTPUT)
332         {
333             FlPrintFile (FileId, "    /*\n");
334         }
335 
336         /* Write one line at a time until we have reached the target line # */
337 
338         while ((Gbl_SourceLine < Gbl_CurrentLine) &&
339                 LsWriteOneSourceLine (FileId))
340         { ; }
341 
342         if (FileId == ASL_FILE_C_SOURCE_OUTPUT)
343         {
344             FlPrintFile (FileId, "     */");
345         }
346 
347         FlPrintFile (FileId, "\n");
348     }
349 }
350 
351 
352 /*******************************************************************************
353  *
354  * FUNCTION:    LsWriteOneSourceLine
355  *
356  * PARAMETERS:  FileId          - ID of current listing file
357  *
358  * RETURN:      FALSE on EOF (input source file), TRUE otherwise
359  *
360  * DESCRIPTION: Read one line from the input source file and echo it to the
361  *              listing file, prefixed with the line number, and if the source
362  *              file contains include files, prefixed with the current filename
363  *
364  ******************************************************************************/
365 
366 UINT32
367 LsWriteOneSourceLine (
368     UINT32                  FileId)
369 {
370     UINT8                   FileByte;
371     UINT32                  Column = 0;
372     UINT32                  Index = 16;
373     BOOLEAN                 StartOfLine = FALSE;
374     BOOLEAN                 ProcessLongLine = FALSE;
375 
376 
377     Gbl_SourceLine++;
378     Gbl_ListingNode->LineNumber++;
379 
380     /* Ignore lines that are completely blank (but count the line above) */
381 
382     if (FlReadFile (ASL_FILE_SOURCE_OUTPUT, &FileByte, 1) != AE_OK)
383     {
384         return (0);
385     }
386     if (FileByte == '\n')
387     {
388         return (1);
389     }
390 
391     /*
392      * This is a non-empty line, we will print the entire line with
393      * the line number and possibly other prefixes and transforms.
394      */
395 
396     /* Line prefixes for special files, C and ASM output */
397 
398     if (FileId == ASL_FILE_C_SOURCE_OUTPUT)
399     {
400         FlPrintFile (FileId, "     *");
401     }
402     if (FileId == ASL_FILE_ASM_SOURCE_OUTPUT)
403     {
404         FlPrintFile (FileId, "; ");
405     }
406 
407     if (Gbl_HasIncludeFiles)
408     {
409         /*
410          * This file contains "include" statements, print the current
411          * filename and line number within the current file
412          */
413         FlPrintFile (FileId, "%12s %5d%s",
414             Gbl_ListingNode->Filename, Gbl_ListingNode->LineNumber,
415             ASL_LISTING_LINE_PREFIX);
416     }
417     else
418     {
419         /* No include files, just print the line number */
420 
421         FlPrintFile (FileId, "%8u%s", Gbl_SourceLine,
422             ASL_LISTING_LINE_PREFIX);
423     }
424 
425     /* Read the rest of this line (up to a newline or EOF) */
426 
427     do
428     {
429         if (FileId == ASL_FILE_C_SOURCE_OUTPUT)
430         {
431             if (FileByte == '/')
432             {
433                 FileByte = '*';
434             }
435         }
436 
437         /* Split long input lines for readability in the listing */
438 
439         Column++;
440         if (Column >= 128)
441         {
442             if (!ProcessLongLine)
443             {
444                 if ((FileByte != '}') &&
445                     (FileByte != '{'))
446                 {
447                     goto WriteByte;
448                 }
449 
450                 ProcessLongLine = TRUE;
451             }
452 
453             if (FileByte == '{')
454             {
455                 FlPrintFile (FileId, "\n%*s{\n", Index, " ");
456                 StartOfLine = TRUE;
457                 Index += 4;
458                 continue;
459             }
460 
461             else if (FileByte == '}')
462             {
463                 if (!StartOfLine)
464                 {
465                     FlPrintFile (FileId, "\n");
466                 }
467 
468                 StartOfLine = TRUE;
469                 Index -= 4;
470                 FlPrintFile (FileId, "%*s}\n", Index, " ");
471                 continue;
472             }
473 
474             /* Ignore spaces/tabs at the start of line */
475 
476             else if ((FileByte == ' ') && StartOfLine)
477             {
478                 continue;
479             }
480 
481             else if (StartOfLine)
482             {
483                 StartOfLine = FALSE;
484                 FlPrintFile (FileId, "%*s", Index, " ");
485             }
486 
487 WriteByte:
488             FlWriteFile (FileId, &FileByte, 1);
489             if (FileByte == '\n')
490             {
491                 /*
492                  * This line has been completed.
493                  * Check if an error occurred on this source line during the compile.
494                  * If so, we print the error message after the source line.
495                  */
496                 LsCheckException (Gbl_SourceLine, FileId);
497                 return (1);
498             }
499         }
500         else
501         {
502             FlWriteFile (FileId, &FileByte, 1);
503             if (FileByte == '\n')
504             {
505                 /*
506                  * This line has been completed.
507                  * Check if an error occurred on this source line during the compile.
508                  * If so, we print the error message after the source line.
509                  */
510                 LsCheckException (Gbl_SourceLine, FileId);
511                 return (1);
512             }
513         }
514 
515     } while (FlReadFile (ASL_FILE_SOURCE_OUTPUT, &FileByte, 1) == AE_OK);
516 
517     /* EOF on the input file was reached */
518 
519     return (0);
520 }
521 
522 
523 /*******************************************************************************
524  *
525  * FUNCTION:    LsFlushListingBuffer
526  *
527  * PARAMETERS:  FileId          - ID of the listing file
528  *
529  * RETURN:      None
530  *
531  * DESCRIPTION: Flush out the current contents of the 16-byte hex AML code
532  *              buffer. Usually called at the termination of a single line
533  *              of source code or when the buffer is full.
534  *
535  ******************************************************************************/
536 
537 void
538 LsFlushListingBuffer (
539     UINT32                  FileId)
540 {
541     UINT32                  i;
542 
543 
544     if (Gbl_CurrentHexColumn == 0)
545     {
546         return;
547     }
548 
549     /* Write the hex bytes */
550 
551     switch (FileId)
552     {
553     case ASL_FILE_LISTING_OUTPUT:
554 
555         for (i = 0; i < Gbl_CurrentHexColumn; i++)
556         {
557             FlPrintFile (FileId, "%2.2X ", Gbl_AmlBuffer[i]);
558         }
559 
560         for (i = 0; i < ((HEX_LISTING_LINE_SIZE - Gbl_CurrentHexColumn) * 3); i++)
561         {
562             FlWriteFile (FileId, ".", 1);
563         }
564 
565         /* Write the ASCII character associated with each of the bytes */
566 
567         LsDumpAscii (FileId, Gbl_CurrentHexColumn, Gbl_AmlBuffer);
568         break;
569 
570 
571     case ASL_FILE_ASM_SOURCE_OUTPUT:
572 
573         for (i = 0; i < Gbl_CurrentHexColumn; i++)
574         {
575             if (i > 0)
576             {
577                 FlPrintFile (FileId, ",");
578             }
579 
580             FlPrintFile (FileId, "0%2.2Xh", Gbl_AmlBuffer[i]);
581         }
582 
583         for (i = 0; i < ((HEX_LISTING_LINE_SIZE - Gbl_CurrentHexColumn) * 5); i++)
584         {
585             FlWriteFile (FileId, " ", 1);
586         }
587 
588         FlPrintFile (FileId, "  ;%8.8X",
589             Gbl_CurrentAmlOffset - HEX_LISTING_LINE_SIZE);
590 
591         /* Write the ASCII character associated with each of the bytes */
592 
593         LsDumpAscii (FileId, Gbl_CurrentHexColumn, Gbl_AmlBuffer);
594         break;
595 
596 
597     case ASL_FILE_C_SOURCE_OUTPUT:
598 
599         for (i = 0; i < Gbl_CurrentHexColumn; i++)
600         {
601             FlPrintFile (FileId, "0x%2.2X,", Gbl_AmlBuffer[i]);
602         }
603 
604         /* Pad hex output with spaces if line is shorter than max line size */
605 
606         for (i = 0; i < ((HEX_LISTING_LINE_SIZE - Gbl_CurrentHexColumn) * 5); i++)
607         {
608             FlWriteFile (FileId, " ", 1);
609         }
610 
611         /* AML offset for the start of the line */
612 
613         FlPrintFile (FileId, "    /* %8.8X",
614             Gbl_CurrentAmlOffset - Gbl_CurrentHexColumn);
615 
616         /* Write the ASCII character associated with each of the bytes */
617 
618         LsDumpAsciiInComment (FileId, Gbl_CurrentHexColumn, Gbl_AmlBuffer);
619         FlPrintFile (FileId, " */");
620         break;
621 
622     default:
623 
624         /* No other types supported */
625 
626         return;
627     }
628 
629     FlPrintFile (FileId, "\n");
630 
631     Gbl_CurrentHexColumn = 0;
632     Gbl_HexBytesWereWritten = TRUE;
633 }
634 
635 
636 /*******************************************************************************
637  *
638  * FUNCTION:    LsPushNode
639  *
640  * PARAMETERS:  Filename        - Pointer to the include filename
641  *
642  * RETURN:      None
643  *
644  * DESCRIPTION: Push a listing node on the listing/include file stack. This
645  *              stack enables tracking of include files (infinitely nested)
646  *              and resumption of the listing of the parent file when the
647  *              include file is finished.
648  *
649  ******************************************************************************/
650 
651 void
652 LsPushNode (
653     char                    *Filename)
654 {
655     ASL_LISTING_NODE        *Lnode;
656 
657 
658     /* Create a new node */
659 
660     Lnode = UtLocalCalloc (sizeof (ASL_LISTING_NODE));
661 
662     /* Initialize */
663 
664     Lnode->Filename = Filename;
665     Lnode->LineNumber = 0;
666 
667     /* Link (push) */
668 
669     Lnode->Next = Gbl_ListingNode;
670     Gbl_ListingNode = Lnode;
671 }
672 
673 
674 /*******************************************************************************
675  *
676  * FUNCTION:    LsPopNode
677  *
678  * PARAMETERS:  None
679  *
680  * RETURN:      List head after current head is popped off
681  *
682  * DESCRIPTION: Pop the current head of the list, free it, and return the
683  *              next node on the stack (the new current node).
684  *
685  ******************************************************************************/
686 
687 ASL_LISTING_NODE *
688 LsPopNode (
689     void)
690 {
691     ASL_LISTING_NODE        *Lnode;
692 
693 
694     /* Just grab the node at the head of the list */
695 
696     Lnode = Gbl_ListingNode;
697     if ((!Lnode) ||
698         (!Lnode->Next))
699     {
700         AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, NULL,
701             "Could not pop empty listing stack");
702         return (Gbl_ListingNode);
703     }
704 
705     Gbl_ListingNode = Lnode->Next;
706     ACPI_FREE (Lnode);
707 
708     /* New "Current" node is the new head */
709 
710     return (Gbl_ListingNode);
711 }
712