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