asllistsup.c revision 249109
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 "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
66void
67LsDumpAscii (
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
109void
110LsDumpAsciiInComment (
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
168void
169LsCheckException (
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
213void
214LsWriteListingHexBytes (
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
294void
295LsWriteSourceLines (
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
364UINT32
365LsWriteOneSourceLine (
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
485WriteByte:
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
535void
536LsFlushListingBuffer (
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
646void
647LsPushNode (
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
682ASL_LISTING_NODE *
683LsPopNode (
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