xref: /freebsd-src/sys/contrib/dev/acpica/compiler/aslerror.c (revision ddd5b8e9b4d8957fce018c520657cdfa4ecffad3)
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 
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                                 /* 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 
479 void
480 AePrintErrorLog (
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 
514 void
515 AslCommonError2 (
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 
600 void
601 AslCommonError (
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 
693 void
694 AslError (
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 
747 void
748 AslCoreSubsystemError (
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 
792 int
793 AslCompilererror (
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