xref: /freebsd/sys/contrib/dev/acpica/compiler/aslerror.c (revision 298cf604ccf133b101c6fad42d1a078a1fac58ca)
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 
52 static void
53 AeAddToErrorLog (
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 
69 void
70 AeClearErrorLog (
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 
103 static void
104 AeAddToErrorLog (
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 
167 void
168 AePrintException (
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 
473 void
474 AePrintErrorLog (
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 
508 void
509 AslCommonError2 (
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 
594 void
595 AslCommonError (
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         CmDoOutputFiles ();
664         CmCleanupAndExit ();
665         exit(1);
666     }
667 
668     return;
669 }
670 
671 
672 /*******************************************************************************
673  *
674  * FUNCTION:    AslError
675  *
676  * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
677  *              MessageId           - Index into global message buffer
678  *              Op                  - Parse node where error happened
679  *              ExtraMessage        - additional error message
680  *
681  * RETURN:      None
682  *
683  * DESCRIPTION: Main error reporting routine for the ASL compiler (all code
684  *              except the parser.)
685  *
686  ******************************************************************************/
687 
688 void
689 AslError (
690     UINT8                   Level,
691     UINT8                   MessageId,
692     ACPI_PARSE_OBJECT       *Op,
693     char                    *ExtraMessage)
694 {
695 
696     switch (Level)
697     {
698     case ASL_WARNING2:
699     case ASL_WARNING3:
700         if (Gbl_WarningLevel < Level)
701         {
702             return;
703         }
704         break;
705 
706     default:
707         break;
708     }
709 
710     if (Op)
711     {
712         AslCommonError (Level, MessageId, Op->Asl.LineNumber,
713                         Op->Asl.LogicalLineNumber,
714                         Op->Asl.LogicalByteOffset,
715                         Op->Asl.Column,
716                         Op->Asl.Filename, ExtraMessage);
717     }
718     else
719     {
720         AslCommonError (Level, MessageId, 0,
721                         0, 0, 0, NULL, ExtraMessage);
722     }
723 }
724 
725 
726 /*******************************************************************************
727  *
728  * FUNCTION:    AslCoreSubsystemError
729  *
730  * PARAMETERS:  Op                  - Parse node where error happened
731  *              Status              - The ACPI CA Exception
732  *              ExtraMessage        - additional error message
733  *              Abort               - TRUE -> Abort compilation
734  *
735  * RETURN:      None
736  *
737  * DESCRIPTION: Error reporting routine for exceptions returned by the ACPI
738  *              CA core subsystem.
739  *
740  ******************************************************************************/
741 
742 void
743 AslCoreSubsystemError (
744     ACPI_PARSE_OBJECT       *Op,
745     ACPI_STATUS             Status,
746     char                    *ExtraMessage,
747     BOOLEAN                 Abort)
748 {
749 
750     sprintf (MsgBuffer, "%s %s", AcpiFormatException (Status), ExtraMessage);
751 
752     if (Op)
753     {
754         AslCommonError (ASL_ERROR, ASL_MSG_CORE_EXCEPTION, Op->Asl.LineNumber,
755                         Op->Asl.LogicalLineNumber,
756                         Op->Asl.LogicalByteOffset,
757                         Op->Asl.Column,
758                         Op->Asl.Filename, MsgBuffer);
759     }
760     else
761     {
762         AslCommonError (ASL_ERROR, ASL_MSG_CORE_EXCEPTION, 0,
763                         0, 0, 0, NULL, MsgBuffer);
764     }
765 
766     if (Abort)
767     {
768         AslAbort ();
769     }
770 }
771 
772 
773 /*******************************************************************************
774  *
775  * FUNCTION:    AslCompilererror
776  *
777  * PARAMETERS:  CompilerMessage         - Error message from the parser
778  *
779  * RETURN:      Status (0 for now)
780  *
781  * DESCRIPTION: Report an error situation discovered in a production
782  *              NOTE: don't change the name of this function, it is called
783  *              from the auto-generated parser.
784  *
785  ******************************************************************************/
786 
787 int
788 AslCompilererror (
789     const char              *CompilerMessage)
790 {
791 
792     AslCommonError (ASL_ERROR, ASL_MSG_SYNTAX, Gbl_CurrentLineNumber,
793         Gbl_LogicalLineNumber, Gbl_CurrentLineOffset,
794         Gbl_CurrentColumn, Gbl_Files[ASL_FILE_INPUT].Filename,
795         ACPI_CAST_PTR (char, CompilerMessage));
796 
797     return (0);
798 }
799