aslerror.c revision 249112
1/******************************************************************************
2 *
3 * Module Name: aslerror - Error handling and statistics
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#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 != 1)
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                                /* Read/write the source line, up to the maximum line length */
306
307                                while (RActual && SourceByte && (SourceByte != '\n'))
308                                {
309                                    if (Total < 256)
310                                    {
311                                        /* After the max line length, we will just read the line, no write */
312
313                                        if (fwrite (&SourceByte, 1, 1, OutputFile) != 1)
314                                        {
315                                            printf ("[*** iASL: Write error on output file ***]\n");
316                                            return;
317                                        }
318                                    }
319                                    else if (Total == 256)
320                                    {
321                                        fprintf (OutputFile,
322                                            "\n[*** iASL: Very long input line, message below refers to column %u ***]",
323                                            Enode->Column);
324                                    }
325
326                                    RActual = fread (&SourceByte, 1, 1, SourceFile);
327                                    if (RActual != 1)
328                                    {
329                                        fprintf (OutputFile,
330                                            "[*** iASL: Read error on source code temp file %s ***]",
331                                            Gbl_Files[ASL_FILE_SOURCE_OUTPUT].Filename);
332                                        return;
333                                    }
334                                    Total++;
335                                }
336                            }
337                        }
338                    }
339
340                    fprintf (OutputFile, "\n");
341                }
342            }
343        }
344        else
345        {
346            /*
347             * Less verbose version of the error message, enabled via the
348             * -vi switch. The format is compatible with MS Visual Studio.
349             */
350            fprintf (OutputFile, "%s", Enode->Filename);
351
352            if (Enode->LineNumber)
353            {
354                fprintf (OutputFile, "(%u) : ",
355                    Enode->LineNumber);
356            }
357        }
358    }
359
360    /* NULL message ID, just print the raw message */
361
362    if (Enode->MessageId == 0)
363    {
364        fprintf (OutputFile, "%s\n", Enode->Message);
365    }
366    else
367    {
368        /* Decode the message ID */
369
370        if (Gbl_VerboseErrors)
371        {
372            fprintf (OutputFile, "%s %4.4d -",
373                        AslErrorLevel[Enode->Level],
374                        Enode->MessageId + ((Enode->Level+1) * 1000));
375        }
376        else /* IDE case */
377        {
378            fprintf (OutputFile, "%s %4.4d:",
379                        AslErrorLevelIde[Enode->Level],
380                        Enode->MessageId + ((Enode->Level+1) * 1000));
381        }
382
383        MainMessage = AslMessages[Enode->MessageId];
384        ExtraMessage = Enode->Message;
385
386        if (Enode->LineNumber)
387        {
388            /* Main message: try to use string from AslMessages first */
389
390            if (!MainMessage)
391            {
392                MainMessage = "";
393            }
394
395            MsgLength = strlen (MainMessage);
396            if (MsgLength == 0)
397            {
398                /* Use the secondary/extra message as main message */
399
400                MainMessage = Enode->Message;
401                if (!MainMessage)
402                {
403                    MainMessage = "";
404                }
405
406                MsgLength = strlen (MainMessage);
407                ExtraMessage = NULL;
408            }
409
410            if (Gbl_VerboseErrors && !PrematureEOF)
411            {
412                if (Total >= 256)
413                {
414                    fprintf (OutputFile, "    %s",
415                        MainMessage);
416                }
417                else
418                {
419                    SourceColumn = Enode->Column + Enode->FilenameLength + 6 + 2;
420                    ErrorColumn = ASL_ERROR_LEVEL_LENGTH + 5 + 2 + 1;
421
422                    if ((MsgLength + ErrorColumn) < (SourceColumn - 1))
423                    {
424                        fprintf (OutputFile, "%*s%s",
425                            (int) ((SourceColumn - 1) - ErrorColumn),
426                            MainMessage, " ^ ");
427                    }
428                    else
429                    {
430                        fprintf (OutputFile, "%*s %s",
431                            (int) ((SourceColumn - ErrorColumn) + 1), "^",
432                            MainMessage);
433                    }
434                }
435            }
436            else
437            {
438                fprintf (OutputFile, " %s", MainMessage);
439            }
440
441            /* Print the extra info message if present */
442
443            if (ExtraMessage)
444            {
445                fprintf (OutputFile, " (%s)", ExtraMessage);
446            }
447
448            if (PrematureEOF)
449            {
450                fprintf (OutputFile, " and premature End-Of-File");
451            }
452
453            fprintf (OutputFile, "\n");
454            if (Gbl_VerboseErrors)
455            {
456                fprintf (OutputFile, "\n");
457            }
458        }
459        else
460        {
461            fprintf (OutputFile, " %s %s\n\n", MainMessage, ExtraMessage);
462        }
463    }
464}
465
466
467/*******************************************************************************
468 *
469 * FUNCTION:    AePrintErrorLog
470 *
471 * PARAMETERS:  FileId           - Where to output the error log
472 *
473 * RETURN:      None
474 *
475 * DESCRIPTION: Print the entire contents of the error log
476 *
477 ******************************************************************************/
478
479void
480AePrintErrorLog (
481    UINT32                  FileId)
482{
483    ASL_ERROR_MSG           *Enode = Gbl_ErrorLog;
484
485
486    /* Walk the error node list */
487
488    while (Enode)
489    {
490        AePrintException (FileId, Enode, NULL);
491        Enode = Enode->Next;
492    }
493}
494
495
496/*******************************************************************************
497 *
498 * FUNCTION:    AslCommonError2
499 *
500 * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
501 *              MessageId           - Index into global message buffer
502 *              LineNumber          - Actual file line number
503 *              Column              - Column in current line
504 *              SourceLine          - Actual source code line
505 *              Filename            - source filename
506 *              ExtraMessage        - additional error message
507 *
508 * RETURN:      None
509 *
510 * DESCRIPTION: Create a new error node and add it to the error log
511 *
512 ******************************************************************************/
513
514void
515AslCommonError2 (
516    UINT8                   Level,
517    UINT8                   MessageId,
518    UINT32                  LineNumber,
519    UINT32                  Column,
520    char                    *SourceLine,
521    char                    *Filename,
522    char                    *ExtraMessage)
523{
524    char                    *MessageBuffer = NULL;
525    char                    *LineBuffer;
526    ASL_ERROR_MSG           *Enode;
527
528
529    Enode = UtLocalCalloc (sizeof (ASL_ERROR_MSG));
530
531    if (ExtraMessage)
532    {
533        /* Allocate a buffer for the message and a new error node */
534
535        MessageBuffer = UtLocalCalloc (strlen (ExtraMessage) + 1);
536
537        /* Keep a copy of the extra message */
538
539        ACPI_STRCPY (MessageBuffer, ExtraMessage);
540    }
541
542    LineBuffer = UtLocalCalloc (strlen (SourceLine) + 1);
543    ACPI_STRCPY (LineBuffer, SourceLine);
544
545    /* Initialize the error node */
546
547    if (Filename)
548    {
549        Enode->Filename       = Filename;
550        Enode->FilenameLength = strlen (Filename);
551        if (Enode->FilenameLength < 6)
552        {
553            Enode->FilenameLength = 6;
554        }
555    }
556
557    Enode->MessageId            = MessageId;
558    Enode->Level                = Level;
559    Enode->LineNumber           = LineNumber;
560    Enode->LogicalLineNumber    = LineNumber;
561    Enode->LogicalByteOffset    = 0;
562    Enode->Column               = Column;
563    Enode->Message              = MessageBuffer;
564    Enode->SourceLine           = LineBuffer;
565
566    /* Add the new node to the error node list */
567
568    AeAddToErrorLog (Enode);
569
570    if (Gbl_DebugFlag)
571    {
572        /* stderr is a file, send error to it immediately */
573
574        AePrintException (ASL_FILE_STDERR, Enode, NULL);
575    }
576
577    Gbl_ExceptionCount[Level]++;
578}
579
580
581/*******************************************************************************
582 *
583 * FUNCTION:    AslCommonError
584 *
585 * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
586 *              MessageId           - Index into global message buffer
587 *              CurrentLineNumber   - Actual file line number
588 *              LogicalLineNumber   - Cumulative line number
589 *              LogicalByteOffset   - Byte offset in source file
590 *              Column              - Column in current line
591 *              Filename            - source filename
592 *              ExtraMessage        - additional error message
593 *
594 * RETURN:      None
595 *
596 * DESCRIPTION: Create a new error node and add it to the error log
597 *
598 ******************************************************************************/
599
600void
601AslCommonError (
602    UINT8                   Level,
603    UINT8                   MessageId,
604    UINT32                  CurrentLineNumber,
605    UINT32                  LogicalLineNumber,
606    UINT32                  LogicalByteOffset,
607    UINT32                  Column,
608    char                    *Filename,
609    char                    *ExtraMessage)
610{
611    UINT32                  MessageSize;
612    char                    *MessageBuffer = NULL;
613    ASL_ERROR_MSG           *Enode;
614
615
616    Enode = UtLocalCalloc (sizeof (ASL_ERROR_MSG));
617
618    if (ExtraMessage)
619    {
620        /* Allocate a buffer for the message and a new error node */
621
622        MessageSize   = strlen (ExtraMessage) + 1;
623        MessageBuffer = UtLocalCalloc (MessageSize);
624
625        /* Keep a copy of the extra message */
626
627        ACPI_STRCPY (MessageBuffer, ExtraMessage);
628    }
629
630    /* Initialize the error node */
631
632    if (Filename)
633    {
634        Enode->Filename       = Filename;
635        Enode->FilenameLength = strlen (Filename);
636        if (Enode->FilenameLength < 6)
637        {
638            Enode->FilenameLength = 6;
639        }
640    }
641
642    Enode->MessageId            = MessageId;
643    Enode->Level                = Level;
644    Enode->LineNumber           = CurrentLineNumber;
645    Enode->LogicalLineNumber    = LogicalLineNumber;
646    Enode->LogicalByteOffset    = LogicalByteOffset;
647    Enode->Column               = Column;
648    Enode->Message              = MessageBuffer;
649    Enode->SourceLine           = NULL;
650
651    /* Add the new node to the error node list */
652
653    AeAddToErrorLog (Enode);
654
655    if (Gbl_DebugFlag)
656    {
657        /* stderr is a file, send error to it immediately */
658
659        AePrintException (ASL_FILE_STDERR, Enode, NULL);
660    }
661
662    Gbl_ExceptionCount[Level]++;
663    if (Gbl_ExceptionCount[ASL_ERROR] > ASL_MAX_ERROR_COUNT)
664    {
665        printf ("\nMaximum error count (%u) exceeded\n", ASL_MAX_ERROR_COUNT);
666
667        Gbl_SourceLine = 0;
668        Gbl_NextError = Gbl_ErrorLog;
669        CmCleanupAndExit ();
670        exit(1);
671    }
672
673    return;
674}
675
676
677/*******************************************************************************
678 *
679 * FUNCTION:    AslError
680 *
681 * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
682 *              MessageId           - Index into global message buffer
683 *              Op                  - Parse node where error happened
684 *              ExtraMessage        - additional error message
685 *
686 * RETURN:      None
687 *
688 * DESCRIPTION: Main error reporting routine for the ASL compiler (all code
689 *              except the parser.)
690 *
691 ******************************************************************************/
692
693void
694AslError (
695    UINT8                   Level,
696    UINT8                   MessageId,
697    ACPI_PARSE_OBJECT       *Op,
698    char                    *ExtraMessage)
699{
700
701    switch (Level)
702    {
703    case ASL_WARNING2:
704    case ASL_WARNING3:
705        if (Gbl_WarningLevel < Level)
706        {
707            return;
708        }
709        break;
710
711    default:
712        break;
713    }
714
715    if (Op)
716    {
717        AslCommonError (Level, MessageId, Op->Asl.LineNumber,
718                        Op->Asl.LogicalLineNumber,
719                        Op->Asl.LogicalByteOffset,
720                        Op->Asl.Column,
721                        Op->Asl.Filename, ExtraMessage);
722    }
723    else
724    {
725        AslCommonError (Level, MessageId, 0,
726                        0, 0, 0, NULL, ExtraMessage);
727    }
728}
729
730
731/*******************************************************************************
732 *
733 * FUNCTION:    AslCoreSubsystemError
734 *
735 * PARAMETERS:  Op                  - Parse node where error happened
736 *              Status              - The ACPI CA Exception
737 *              ExtraMessage        - additional error message
738 *              Abort               - TRUE -> Abort compilation
739 *
740 * RETURN:      None
741 *
742 * DESCRIPTION: Error reporting routine for exceptions returned by the ACPI
743 *              CA core subsystem.
744 *
745 ******************************************************************************/
746
747void
748AslCoreSubsystemError (
749    ACPI_PARSE_OBJECT       *Op,
750    ACPI_STATUS             Status,
751    char                    *ExtraMessage,
752    BOOLEAN                 Abort)
753{
754
755    sprintf (MsgBuffer, "%s %s", AcpiFormatException (Status), ExtraMessage);
756
757    if (Op)
758    {
759        AslCommonError (ASL_ERROR, ASL_MSG_CORE_EXCEPTION, Op->Asl.LineNumber,
760                        Op->Asl.LogicalLineNumber,
761                        Op->Asl.LogicalByteOffset,
762                        Op->Asl.Column,
763                        Op->Asl.Filename, MsgBuffer);
764    }
765    else
766    {
767        AslCommonError (ASL_ERROR, ASL_MSG_CORE_EXCEPTION, 0,
768                        0, 0, 0, NULL, MsgBuffer);
769    }
770
771    if (Abort)
772    {
773        AslAbort ();
774    }
775}
776
777
778/*******************************************************************************
779 *
780 * FUNCTION:    AslCompilererror
781 *
782 * PARAMETERS:  CompilerMessage         - Error message from the parser
783 *
784 * RETURN:      Status (0 for now)
785 *
786 * DESCRIPTION: Report an error situation discovered in a production
787 *              NOTE: don't change the name of this function, it is called
788 *              from the auto-generated parser.
789 *
790 ******************************************************************************/
791
792int
793AslCompilererror (
794    const char              *CompilerMessage)
795{
796
797    AslCommonError (ASL_ERROR, ASL_MSG_SYNTAX, Gbl_CurrentLineNumber,
798        Gbl_LogicalLineNumber, Gbl_CurrentLineOffset,
799        Gbl_CurrentColumn, Gbl_Files[ASL_FILE_INPUT].Filename,
800        ACPI_CAST_PTR (char, CompilerMessage));
801
802    return (0);
803}
804