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