xref: /freebsd/sys/contrib/dev/acpica/compiler/asllistsup.c (revision 39ee7a7a6bdd1557b1c3532abf60d139798ac88b)
1 /******************************************************************************
2  *
3  * Module Name: asllistsup - Listing file support utilities
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 <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 
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             FlPrintFile (FileId, "0%2.2Xh", Gbl_AmlBuffer[i]);
580         }
581 
582         for (i = 0; i < ((HEX_LISTING_LINE_SIZE - Gbl_CurrentHexColumn) * 5); i++)
583         {
584             FlWriteFile (FileId, " ", 1);
585         }
586 
587         FlPrintFile (FileId, "  ;%8.8X",
588             Gbl_CurrentAmlOffset - HEX_LISTING_LINE_SIZE);
589 
590         /* Write the ASCII character associated with each of the bytes */
591 
592         LsDumpAscii (FileId, Gbl_CurrentHexColumn, Gbl_AmlBuffer);
593         break;
594 
595 
596     case ASL_FILE_C_SOURCE_OUTPUT:
597 
598         for (i = 0; i < Gbl_CurrentHexColumn; i++)
599         {
600             FlPrintFile (FileId, "0x%2.2X,", Gbl_AmlBuffer[i]);
601         }
602 
603         /* Pad hex output with spaces if line is shorter than max line size */
604 
605         for (i = 0; i < ((HEX_LISTING_LINE_SIZE - Gbl_CurrentHexColumn) * 5); i++)
606         {
607             FlWriteFile (FileId, " ", 1);
608         }
609 
610         /* AML offset for the start of the line */
611 
612         FlPrintFile (FileId, "    /* %8.8X",
613             Gbl_CurrentAmlOffset - Gbl_CurrentHexColumn);
614 
615         /* Write the ASCII character associated with each of the bytes */
616 
617         LsDumpAsciiInComment (FileId, Gbl_CurrentHexColumn, Gbl_AmlBuffer);
618         FlPrintFile (FileId, " */");
619         break;
620 
621     default:
622 
623         /* No other types supported */
624 
625         return;
626     }
627 
628     FlPrintFile (FileId, "\n");
629 
630     Gbl_CurrentHexColumn = 0;
631     Gbl_HexBytesWereWritten = TRUE;
632 }
633 
634 
635 /*******************************************************************************
636  *
637  * FUNCTION:    LsPushNode
638  *
639  * PARAMETERS:  Filename        - Pointer to the include filename
640  *
641  * RETURN:      None
642  *
643  * DESCRIPTION: Push a listing node on the listing/include file stack. This
644  *              stack enables tracking of include files (infinitely nested)
645  *              and resumption of the listing of the parent file when the
646  *              include file is finished.
647  *
648  ******************************************************************************/
649 
650 void
651 LsPushNode (
652     char                    *Filename)
653 {
654     ASL_LISTING_NODE        *Lnode;
655 
656 
657     /* Create a new node */
658 
659     Lnode = UtLocalCalloc (sizeof (ASL_LISTING_NODE));
660 
661     /* Initialize */
662 
663     Lnode->Filename = Filename;
664     Lnode->LineNumber = 0;
665 
666     /* Link (push) */
667 
668     Lnode->Next = Gbl_ListingNode;
669     Gbl_ListingNode = Lnode;
670 }
671 
672 
673 /*******************************************************************************
674  *
675  * FUNCTION:    LsPopNode
676  *
677  * PARAMETERS:  None
678  *
679  * RETURN:      List head after current head is popped off
680  *
681  * DESCRIPTION: Pop the current head of the list, free it, and return the
682  *              next node on the stack (the new current node).
683  *
684  ******************************************************************************/
685 
686 ASL_LISTING_NODE *
687 LsPopNode (
688     void)
689 {
690     ASL_LISTING_NODE        *Lnode;
691 
692 
693     /* Just grab the node at the head of the list */
694 
695     Lnode = Gbl_ListingNode;
696     if ((!Lnode) ||
697         (!Lnode->Next))
698     {
699         AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, NULL,
700             "Could not pop empty listing stack");
701         return (Gbl_ListingNode);
702     }
703 
704     Gbl_ListingNode = Lnode->Next;
705     ACPI_FREE (Lnode);
706 
707     /* New "Current" node is the new head */
708 
709     return (Gbl_ListingNode);
710 }
711