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