aslerror.c revision 241973
1/******************************************************************************
2 *
3 * Module Name: aslerror - Error handling and statistics
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2012, 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#define ASL_EXCEPTIONS
45#include <contrib/dev/acpica/compiler/aslcompiler.h>
46
47#define _COMPONENT          ACPI_COMPILER
48        ACPI_MODULE_NAME    ("aslerror")
49
50/* Local prototypes */
51
52static void
53AeAddToErrorLog (
54    ASL_ERROR_MSG           *Enode);
55
56
57/*******************************************************************************
58 *
59 * FUNCTION:    AeClearErrorLog
60 *
61 * PARAMETERS:  None
62 *
63 * RETURN:      None
64 *
65 * DESCRIPTION: Empty the error list
66 *
67 ******************************************************************************/
68
69void
70AeClearErrorLog (
71    void)
72{
73    ASL_ERROR_MSG           *Enode = Gbl_ErrorLog;
74    ASL_ERROR_MSG           *Next;
75
76    /* Walk the error node list */
77
78    while (Enode)
79    {
80        Next = Enode->Next;
81        ACPI_FREE (Enode);
82        Enode = Next;
83    }
84
85    Gbl_ErrorLog = NULL;
86}
87
88
89/*******************************************************************************
90 *
91 * FUNCTION:    AeAddToErrorLog
92 *
93 * PARAMETERS:  Enode       - An error node to add to the log
94 *
95 * RETURN:      None
96 *
97 * DESCRIPTION: Add a new error node to the error log. The error log is
98 *              ordered by the "logical" line number (cumulative line number
99 *              including all include files.)
100 *
101 ******************************************************************************/
102
103static void
104AeAddToErrorLog (
105    ASL_ERROR_MSG           *Enode)
106{
107    ASL_ERROR_MSG           *Next;
108    ASL_ERROR_MSG           *Prev;
109
110
111    /* If Gbl_ErrorLog is null, this is the first error node */
112
113    if (!Gbl_ErrorLog)
114    {
115        Gbl_ErrorLog = Enode;
116        return;
117    }
118
119    /*
120     * Walk error list until we find a line number greater than ours.
121     * List is sorted according to line number.
122     */
123    Prev = NULL;
124    Next = Gbl_ErrorLog;
125
126    while ((Next) &&
127           (Next->LogicalLineNumber <= Enode->LogicalLineNumber))
128    {
129        Prev = Next;
130        Next = Next->Next;
131    }
132
133    /* Found our place in the list */
134
135    Enode->Next = Next;
136
137    if (Prev)
138    {
139        Prev->Next = Enode;
140    }
141    else
142    {
143        Gbl_ErrorLog = Enode;
144    }
145}
146
147
148/*******************************************************************************
149 *
150 * FUNCTION:    AePrintException
151 *
152 * PARAMETERS:  FileId          - ID of output file
153 *              Enode           - Error node to print
154 *              Header          - Additional text before each message
155 *
156 * RETURN:      None
157 *
158 * DESCRIPTION: Print the contents of an error node.
159 *
160 * NOTE:        We don't use the FlxxxFile I/O functions here because on error
161 *              they abort the compiler and call this function!  Since we
162 *              are reporting errors here, we ignore most output errors and
163 *              just try to get out as much as we can.
164 *
165 ******************************************************************************/
166
167void
168AePrintException (
169    UINT32                  FileId,
170    ASL_ERROR_MSG           *Enode,
171    char                    *Header)
172{
173    UINT8                   SourceByte;
174    int                     Actual;
175    size_t                  RActual;
176    UINT32                  MsgLength;
177    char                    *MainMessage;
178    char                    *ExtraMessage;
179    UINT32                  SourceColumn;
180    UINT32                  ErrorColumn;
181    FILE                    *OutputFile;
182    FILE                    *SourceFile = NULL;
183    long                    FileSize;
184    BOOLEAN                 PrematureEOF = FALSE;
185    UINT32                  Total = 0;
186
187
188    if (Gbl_NoErrors)
189    {
190        return;
191    }
192
193    /*
194     * Only listing files have a header, and remarks/optimizations
195     * are always output
196     */
197    if (!Header)
198    {
199        /* Ignore remarks if requested */
200
201        switch (Enode->Level)
202        {
203        case ASL_REMARK:
204            if (!Gbl_DisplayRemarks)
205            {
206                return;
207            }
208            break;
209
210        case ASL_OPTIMIZATION:
211            if (!Gbl_DisplayOptimizations)
212            {
213                return;
214            }
215            break;
216
217        default:
218            break;
219        }
220    }
221
222    /* Get the file handles */
223
224    OutputFile = Gbl_Files[FileId].Handle;
225
226
227    if (!Enode->SourceLine)
228    {
229        /* Use the merged header/source file if present, otherwise use input file */
230
231        SourceFile = Gbl_Files[ASL_FILE_SOURCE_OUTPUT].Handle;
232        if (!SourceFile)
233        {
234            SourceFile = Gbl_Files[ASL_FILE_INPUT].Handle;
235        }
236
237        if (SourceFile)
238        {
239            /* Determine if the error occurred at source file EOF */
240
241            fseek (SourceFile, 0, SEEK_END);
242            FileSize = ftell (SourceFile);
243
244            if ((long) Enode->LogicalByteOffset >= FileSize)
245            {
246                PrematureEOF = TRUE;
247            }
248        }
249    }
250
251    if (Header)
252    {
253        fprintf (OutputFile, "%s", Header);
254    }
255
256    /* Print filename and line number if present and valid */
257
258    if (Enode->Filename)
259    {
260        if (Gbl_VerboseErrors)
261        {
262            fprintf (OutputFile, "%-8s", Enode->Filename);
263
264            if (Enode->LineNumber)
265            {
266                if (Enode->SourceLine)
267                {
268                    fprintf (OutputFile, " %6u: %s",
269                        Enode->LineNumber, Enode->SourceLine);
270                }
271                else
272                {
273                    fprintf (OutputFile, " %6u: ", Enode->LineNumber);
274
275                    /*
276                     * If not at EOF, get the corresponding source code line and
277                     * display it. Don't attempt this if we have a premature EOF
278                     * condition.
279                     */
280                    if (!PrematureEOF)
281                    {
282                        /*
283                         * Seek to the offset in the combined source file, read
284                         * the source line, and write it to the output.
285                         */
286                        Actual = fseek (SourceFile, (long) Enode->LogicalByteOffset,
287                                    (int) SEEK_SET);
288                        if (Actual)
289                        {
290                            fprintf (OutputFile,
291                                "[*** iASL: Seek error on source code temp file %s ***]",
292                                Gbl_Files[ASL_FILE_SOURCE_OUTPUT].Filename);
293                        }
294                        else
295                        {
296                            RActual = fread (&SourceByte, 1, 1, SourceFile);
297                            if (!RActual)
298                            {
299                                fprintf (OutputFile,
300                                    "[*** iASL: Read error on source code temp file %s ***]",
301                                    Gbl_Files[ASL_FILE_SOURCE_OUTPUT].Filename);
302                            }
303                            else
304                            {
305                                while (RActual && SourceByte && (SourceByte != '\n') && (Total < 256))
306                                {
307                                    fwrite (&SourceByte, 1, 1, OutputFile);
308                                    RActual = fread (&SourceByte, 1, 1, SourceFile);
309                                    Total++;
310                                }
311
312                                if (Total >= 256)
313                                {
314                                    fprintf (OutputFile,
315                                        "\n[*** iASL: Long input line, an error occurred at column %u ***]",
316                                        Enode->Column);
317                                }
318                            }
319                        }
320                    }
321
322                    fprintf (OutputFile, "\n");
323                }
324            }
325        }
326        else
327        {
328            /*
329             * Less verbose version of the error message, enabled via the
330             * -vi switch. The format is compatible with MS Visual Studio.
331             */
332            fprintf (OutputFile, "%s", Enode->Filename);
333
334            if (Enode->LineNumber)
335            {
336                fprintf (OutputFile, "(%u) : ",
337                    Enode->LineNumber);
338            }
339        }
340    }
341
342    /* NULL message ID, just print the raw message */
343
344    if (Enode->MessageId == 0)
345    {
346        fprintf (OutputFile, "%s\n", Enode->Message);
347    }
348    else
349    {
350        /* Decode the message ID */
351
352        if (Gbl_VerboseErrors)
353        {
354            fprintf (OutputFile, "%s %4.4d -",
355                        AslErrorLevel[Enode->Level],
356                        Enode->MessageId + ((Enode->Level+1) * 1000));
357        }
358        else /* IDE case */
359        {
360            fprintf (OutputFile, "%s %4.4d:",
361                        AslErrorLevelIde[Enode->Level],
362                        Enode->MessageId + ((Enode->Level+1) * 1000));
363        }
364
365        MainMessage = AslMessages[Enode->MessageId];
366        ExtraMessage = Enode->Message;
367
368        if (Enode->LineNumber)
369        {
370            /* Main message: try to use string from AslMessages first */
371
372            if (!MainMessage)
373            {
374                MainMessage = "";
375            }
376
377            MsgLength = strlen (MainMessage);
378            if (MsgLength == 0)
379            {
380                /* Use the secondary/extra message as main message */
381
382                MainMessage = Enode->Message;
383                if (!MainMessage)
384                {
385                    MainMessage = "";
386                }
387
388                MsgLength = strlen (MainMessage);
389                ExtraMessage = NULL;
390            }
391
392            if (Gbl_VerboseErrors && !PrematureEOF)
393            {
394                if (Total >= 256)
395                {
396                    fprintf (OutputFile, "    %s",
397                        MainMessage);
398                }
399                else
400                {
401                    SourceColumn = Enode->Column + Enode->FilenameLength + 6 + 2;
402                    ErrorColumn = ASL_ERROR_LEVEL_LENGTH + 5 + 2 + 1;
403
404                    if ((MsgLength + ErrorColumn) < (SourceColumn - 1))
405                    {
406                        fprintf (OutputFile, "%*s%s",
407                            (int) ((SourceColumn - 1) - ErrorColumn),
408                            MainMessage, " ^ ");
409                    }
410                    else
411                    {
412                        fprintf (OutputFile, "%*s %s",
413                            (int) ((SourceColumn - ErrorColumn) + 1), "^",
414                            MainMessage);
415                    }
416                }
417            }
418            else
419            {
420                fprintf (OutputFile, " %s", MainMessage);
421            }
422
423            /* Print the extra info message if present */
424
425            if (ExtraMessage)
426            {
427                fprintf (OutputFile, " (%s)", ExtraMessage);
428            }
429
430            if (PrematureEOF)
431            {
432                fprintf (OutputFile, " and premature End-Of-File");
433            }
434
435            fprintf (OutputFile, "\n");
436            if (Gbl_VerboseErrors)
437            {
438                fprintf (OutputFile, "\n");
439            }
440        }
441        else
442        {
443            fprintf (OutputFile, " %s %s\n\n", MainMessage, ExtraMessage);
444        }
445    }
446}
447
448
449/*******************************************************************************
450 *
451 * FUNCTION:    AePrintErrorLog
452 *
453 * PARAMETERS:  FileId           - Where to output the error log
454 *
455 * RETURN:      None
456 *
457 * DESCRIPTION: Print the entire contents of the error log
458 *
459 ******************************************************************************/
460
461void
462AePrintErrorLog (
463    UINT32                  FileId)
464{
465    ASL_ERROR_MSG           *Enode = Gbl_ErrorLog;
466
467
468    /* Walk the error node list */
469
470    while (Enode)
471    {
472        AePrintException (FileId, Enode, NULL);
473        Enode = Enode->Next;
474    }
475}
476
477
478/*******************************************************************************
479 *
480 * FUNCTION:    AslCommonError2
481 *
482 * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
483 *              MessageId           - Index into global message buffer
484 *              LineNumber          - Actual file line number
485 *              Column              - Column in current line
486 *              SourceLine          - Actual source code line
487 *              Filename            - source filename
488 *              ExtraMessage        - additional error message
489 *
490 * RETURN:      None
491 *
492 * DESCRIPTION: Create a new error node and add it to the error log
493 *
494 ******************************************************************************/
495
496void
497AslCommonError2 (
498    UINT8                   Level,
499    UINT8                   MessageId,
500    UINT32                  LineNumber,
501    UINT32                  Column,
502    char                    *SourceLine,
503    char                    *Filename,
504    char                    *ExtraMessage)
505{
506    char                    *MessageBuffer = NULL;
507    char                    *LineBuffer;
508    ASL_ERROR_MSG           *Enode;
509
510
511    Enode = UtLocalCalloc (sizeof (ASL_ERROR_MSG));
512
513    if (ExtraMessage)
514    {
515        /* Allocate a buffer for the message and a new error node */
516
517        MessageBuffer = UtLocalCalloc (strlen (ExtraMessage) + 1);
518
519        /* Keep a copy of the extra message */
520
521        ACPI_STRCPY (MessageBuffer, ExtraMessage);
522    }
523
524    LineBuffer = UtLocalCalloc (strlen (SourceLine) + 1);
525    ACPI_STRCPY (LineBuffer, SourceLine);
526
527    /* Initialize the error node */
528
529    if (Filename)
530    {
531        Enode->Filename       = Filename;
532        Enode->FilenameLength = strlen (Filename);
533        if (Enode->FilenameLength < 6)
534        {
535            Enode->FilenameLength = 6;
536        }
537    }
538
539    Enode->MessageId            = MessageId;
540    Enode->Level                = Level;
541    Enode->LineNumber           = LineNumber;
542    Enode->LogicalLineNumber    = LineNumber;
543    Enode->LogicalByteOffset    = 0;
544    Enode->Column               = Column;
545    Enode->Message              = MessageBuffer;
546    Enode->SourceLine           = LineBuffer;
547
548    /* Add the new node to the error node list */
549
550    AeAddToErrorLog (Enode);
551
552    if (Gbl_DebugFlag)
553    {
554        /* stderr is a file, send error to it immediately */
555
556        AePrintException (ASL_FILE_STDERR, Enode, NULL);
557    }
558
559    Gbl_ExceptionCount[Level]++;
560}
561
562
563/*******************************************************************************
564 *
565 * FUNCTION:    AslCommonError
566 *
567 * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
568 *              MessageId           - Index into global message buffer
569 *              CurrentLineNumber   - Actual file line number
570 *              LogicalLineNumber   - Cumulative line number
571 *              LogicalByteOffset   - Byte offset in source file
572 *              Column              - Column in current line
573 *              Filename            - source filename
574 *              ExtraMessage        - additional error message
575 *
576 * RETURN:      None
577 *
578 * DESCRIPTION: Create a new error node and add it to the error log
579 *
580 ******************************************************************************/
581
582void
583AslCommonError (
584    UINT8                   Level,
585    UINT8                   MessageId,
586    UINT32                  CurrentLineNumber,
587    UINT32                  LogicalLineNumber,
588    UINT32                  LogicalByteOffset,
589    UINT32                  Column,
590    char                    *Filename,
591    char                    *ExtraMessage)
592{
593    UINT32                  MessageSize;
594    char                    *MessageBuffer = NULL;
595    ASL_ERROR_MSG           *Enode;
596
597
598    Enode = UtLocalCalloc (sizeof (ASL_ERROR_MSG));
599
600    if (ExtraMessage)
601    {
602        /* Allocate a buffer for the message and a new error node */
603
604        MessageSize   = strlen (ExtraMessage) + 1;
605        MessageBuffer = UtLocalCalloc (MessageSize);
606
607        /* Keep a copy of the extra message */
608
609        ACPI_STRCPY (MessageBuffer, ExtraMessage);
610    }
611
612    /* Initialize the error node */
613
614    if (Filename)
615    {
616        Enode->Filename       = Filename;
617        Enode->FilenameLength = strlen (Filename);
618        if (Enode->FilenameLength < 6)
619        {
620            Enode->FilenameLength = 6;
621        }
622    }
623
624    Enode->MessageId            = MessageId;
625    Enode->Level                = Level;
626    Enode->LineNumber           = CurrentLineNumber;
627    Enode->LogicalLineNumber    = LogicalLineNumber;
628    Enode->LogicalByteOffset    = LogicalByteOffset;
629    Enode->Column               = Column;
630    Enode->Message              = MessageBuffer;
631    Enode->SourceLine           = NULL;
632
633    /* Add the new node to the error node list */
634
635    AeAddToErrorLog (Enode);
636
637    if (Gbl_DebugFlag)
638    {
639        /* stderr is a file, send error to it immediately */
640
641        AePrintException (ASL_FILE_STDERR, Enode, NULL);
642    }
643
644    Gbl_ExceptionCount[Level]++;
645    if (Gbl_ExceptionCount[ASL_ERROR] > ASL_MAX_ERROR_COUNT)
646    {
647        printf ("\nMaximum error count (%u) exceeded\n", ASL_MAX_ERROR_COUNT);
648
649        Gbl_SourceLine = 0;
650        Gbl_NextError = Gbl_ErrorLog;
651        CmDoOutputFiles ();
652        CmCleanupAndExit ();
653        exit(1);
654    }
655
656    return;
657}
658
659
660/*******************************************************************************
661 *
662 * FUNCTION:    AslError
663 *
664 * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
665 *              MessageId           - Index into global message buffer
666 *              Op                  - Parse node where error happened
667 *              ExtraMessage        - additional error message
668 *
669 * RETURN:      None
670 *
671 * DESCRIPTION: Main error reporting routine for the ASL compiler (all code
672 *              except the parser.)
673 *
674 ******************************************************************************/
675
676void
677AslError (
678    UINT8                   Level,
679    UINT8                   MessageId,
680    ACPI_PARSE_OBJECT       *Op,
681    char                    *ExtraMessage)
682{
683
684    switch (Level)
685    {
686    case ASL_WARNING2:
687    case ASL_WARNING3:
688        if (Gbl_WarningLevel < Level)
689        {
690            return;
691        }
692        break;
693
694    default:
695        break;
696    }
697
698    if (Op)
699    {
700        AslCommonError (Level, MessageId, Op->Asl.LineNumber,
701                        Op->Asl.LogicalLineNumber,
702                        Op->Asl.LogicalByteOffset,
703                        Op->Asl.Column,
704                        Op->Asl.Filename, ExtraMessage);
705    }
706    else
707    {
708        AslCommonError (Level, MessageId, 0,
709                        0, 0, 0, NULL, ExtraMessage);
710    }
711}
712
713
714/*******************************************************************************
715 *
716 * FUNCTION:    AslCoreSubsystemError
717 *
718 * PARAMETERS:  Op                  - Parse node where error happened
719 *              Status              - The ACPI CA Exception
720 *              ExtraMessage        - additional error message
721 *              Abort               - TRUE -> Abort compilation
722 *
723 * RETURN:      None
724 *
725 * DESCRIPTION: Error reporting routine for exceptions returned by the ACPI
726 *              CA core subsystem.
727 *
728 ******************************************************************************/
729
730void
731AslCoreSubsystemError (
732    ACPI_PARSE_OBJECT       *Op,
733    ACPI_STATUS             Status,
734    char                    *ExtraMessage,
735    BOOLEAN                 Abort)
736{
737
738    sprintf (MsgBuffer, "%s %s", AcpiFormatException (Status), ExtraMessage);
739
740    if (Op)
741    {
742        AslCommonError (ASL_ERROR, ASL_MSG_CORE_EXCEPTION, Op->Asl.LineNumber,
743                        Op->Asl.LogicalLineNumber,
744                        Op->Asl.LogicalByteOffset,
745                        Op->Asl.Column,
746                        Op->Asl.Filename, MsgBuffer);
747    }
748    else
749    {
750        AslCommonError (ASL_ERROR, ASL_MSG_CORE_EXCEPTION, 0,
751                        0, 0, 0, NULL, MsgBuffer);
752    }
753
754    if (Abort)
755    {
756        AslAbort ();
757    }
758}
759
760
761/*******************************************************************************
762 *
763 * FUNCTION:    AslCompilererror
764 *
765 * PARAMETERS:  CompilerMessage         - Error message from the parser
766 *
767 * RETURN:      Status (0 for now)
768 *
769 * DESCRIPTION: Report an error situation discovered in a production
770 *              NOTE: don't change the name of this function, it is called
771 *              from the auto-generated parser.
772 *
773 ******************************************************************************/
774
775int
776AslCompilererror (
777    const char              *CompilerMessage)
778{
779
780    AslCommonError (ASL_ERROR, ASL_MSG_SYNTAX, Gbl_CurrentLineNumber,
781        Gbl_LogicalLineNumber, Gbl_CurrentLineOffset,
782        Gbl_CurrentColumn, Gbl_Files[ASL_FILE_INPUT].Filename,
783        ACPI_CAST_PTR (char, CompilerMessage));
784
785    return (0);
786}
787