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