xref: /freebsd/sys/contrib/dev/acpica/compiler/aslerror.c (revision bb15ca603fa442c72dde3f3cb8b46db6970e3950)
1 
2 /******************************************************************************
3  *
4  * Module Name: aslerror - Error handling and statistics
5  *
6  *****************************************************************************/
7 
8 /*
9  * Copyright (C) 2000 - 2011, 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 void
59 AeClearErrorLog (
60     void)
61 {
62     ASL_ERROR_MSG           *Enode = Gbl_ErrorLog;
63     ASL_ERROR_MSG           *Next;
64 
65     /* Walk the error node list */
66 
67     while (Enode)
68     {
69         Next = Enode->Next;
70         ACPI_FREE (Enode);
71         Enode = Next;
72     }
73 
74     Gbl_ErrorLog = NULL;
75 }
76 
77 
78 /*******************************************************************************
79  *
80  * FUNCTION:    AeAddToErrorLog
81  *
82  * PARAMETERS:  Enode       - An error node to add to the log
83  *
84  * RETURN:      None
85  *
86  * DESCRIPTION: Add a new error node to the error log.  The error log is
87  *              ordered by the "logical" line number (cumulative line number
88  *              including all include files.)
89  *
90  ******************************************************************************/
91 
92 static void
93 AeAddToErrorLog (
94     ASL_ERROR_MSG           *Enode)
95 {
96     ASL_ERROR_MSG           *Next;
97     ASL_ERROR_MSG           *Prev;
98 
99 
100     /* If Gbl_ErrorLog is null, this is the first error node */
101 
102     if (!Gbl_ErrorLog)
103     {
104         Gbl_ErrorLog = Enode;
105         return;
106     }
107 
108     /*
109      * Walk error list until we find a line number greater than ours.
110      * List is sorted according to line number.
111      */
112     Prev = NULL;
113     Next = Gbl_ErrorLog;
114 
115     while ((Next) &&
116            (Next->LogicalLineNumber <= Enode->LogicalLineNumber))
117     {
118         Prev = Next;
119         Next = Next->Next;
120     }
121 
122     /* Found our place in the list */
123 
124     Enode->Next = Next;
125 
126     if (Prev)
127     {
128         Prev->Next = Enode;
129     }
130     else
131     {
132         Gbl_ErrorLog = Enode;
133     }
134 }
135 
136 
137 /*******************************************************************************
138  *
139  * FUNCTION:    AePrintException
140  *
141  * PARAMETERS:  FileId          - ID of output file
142  *              Enode           - Error node to print
143  *              Header          - Additional text before each message
144  *
145  * RETURN:      None
146  *
147  * DESCRIPTION: Print the contents of an error node.
148  *
149  * NOTE:        We don't use the FlxxxFile I/O functions here because on error
150  *              they abort the compiler and call this function!  Since we
151  *              are reporting errors here, we ignore most output errors and
152  *              just try to get out as much as we can.
153  *
154  ******************************************************************************/
155 
156 void
157 AePrintException (
158     UINT32                  FileId,
159     ASL_ERROR_MSG           *Enode,
160     char                    *Header)
161 {
162     UINT8                   SourceByte;
163     int                     Actual;
164     size_t                  RActual;
165     UINT32                  MsgLength;
166     char                    *MainMessage;
167     char                    *ExtraMessage;
168     UINT32                  SourceColumn;
169     UINT32                  ErrorColumn;
170     FILE                    *OutputFile;
171     FILE                    *SourceFile;
172     long                    FileSize;
173     BOOLEAN                 PrematureEOF = FALSE;
174 
175 
176     if (Gbl_NoErrors)
177     {
178         return;
179     }
180 
181     /*
182      * Only listing files have a header, and remarks/optimizations
183      * are always output
184      */
185     if (!Header)
186     {
187         /* Ignore remarks if requested */
188 
189         switch (Enode->Level)
190         {
191         case ASL_REMARK:
192             if (!Gbl_DisplayRemarks)
193             {
194                 return;
195             }
196             break;
197 
198         case ASL_OPTIMIZATION:
199             if (!Gbl_DisplayOptimizations)
200             {
201                 return;
202             }
203             break;
204 
205         default:
206             break;
207         }
208     }
209 
210     /* Get the file handles */
211 
212     OutputFile = Gbl_Files[FileId].Handle;
213 
214     /* Use the merged header/source file if present, otherwise use input file */
215 
216     SourceFile = Gbl_Files[ASL_FILE_SOURCE_OUTPUT].Handle;
217     if (!SourceFile)
218     {
219         SourceFile = Gbl_Files[ASL_FILE_INPUT].Handle;
220     }
221 
222     if (SourceFile)
223     {
224         /* Determine if the error occurred at source file EOF */
225 
226         fseek (SourceFile, 0, SEEK_END);
227         FileSize = ftell (SourceFile);
228 
229         if ((long) Enode->LogicalByteOffset >= FileSize)
230         {
231             PrematureEOF = TRUE;
232         }
233     }
234 
235     if (Header)
236     {
237         fprintf (OutputFile, "%s", Header);
238     }
239 
240     /* Print filename and line number if present and valid */
241 
242     if (Enode->Filename)
243     {
244         if (Gbl_VerboseErrors)
245         {
246             fprintf (OutputFile, "%6s", Enode->Filename);
247 
248             if (Enode->LineNumber)
249             {
250                 fprintf (OutputFile, " %6u: ", Enode->LineNumber);
251 
252                 /*
253                  * If not at EOF, get the corresponding source code line and
254                  * display it. Don't attempt this if we have a premature EOF
255                  * condition.
256                  */
257                 if (!PrematureEOF)
258                 {
259                     /*
260                      * Seek to the offset in the combined source file, read
261                      * the source line, and write it to the output.
262                      */
263                     Actual = fseek (SourceFile, (long) Enode->LogicalByteOffset,
264                                 (int) SEEK_SET);
265                     if (Actual)
266                     {
267                         fprintf (OutputFile,
268                             "[*** iASL: Seek error on source code temp file %s ***]",
269                             Gbl_Files[ASL_FILE_SOURCE_OUTPUT].Filename);
270                     }
271                     else
272                     {
273                         RActual = fread (&SourceByte, 1, 1, SourceFile);
274                         if (!RActual)
275                         {
276                             fprintf (OutputFile,
277                                 "[*** iASL: Read error on source code temp file %s ***]",
278                                 Gbl_Files[ASL_FILE_SOURCE_OUTPUT].Filename);
279                         }
280 
281                         else while (RActual && SourceByte && (SourceByte != '\n'))
282                         {
283                             fwrite (&SourceByte, 1, 1, OutputFile);
284                             RActual = fread (&SourceByte, 1, 1, SourceFile);
285                         }
286                     }
287                 }
288 
289                 fprintf (OutputFile, "\n");
290             }
291         }
292         else
293         {
294             fprintf (OutputFile, "%s", Enode->Filename);
295 
296             if (Enode->LineNumber)
297             {
298                 fprintf (OutputFile, "(%u) : ", Enode->LineNumber);
299             }
300         }
301     }
302 
303     /* NULL message ID, just print the raw message */
304 
305     if (Enode->MessageId == 0)
306     {
307         fprintf (OutputFile, "%s\n", Enode->Message);
308     }
309     else
310     {
311         /* Decode the message ID */
312 
313         fprintf (OutputFile, "%s %4.4d - ",
314                     AslErrorLevel[Enode->Level],
315                     Enode->MessageId + ((Enode->Level+1) * 1000));
316 
317         MainMessage = AslMessages[Enode->MessageId];
318         ExtraMessage = Enode->Message;
319 
320         if (Enode->LineNumber)
321         {
322             /* Main message: try to use string from AslMessages first */
323 
324             if (!MainMessage)
325             {
326                 MainMessage = "";
327             }
328 
329             MsgLength = strlen (MainMessage);
330             if (MsgLength == 0)
331             {
332                 /* Use the secondary/extra message as main message */
333 
334                 MainMessage = Enode->Message;
335                 if (!MainMessage)
336                 {
337                     MainMessage = "";
338                 }
339 
340                 MsgLength = strlen (MainMessage);
341                 ExtraMessage = NULL;
342             }
343 
344             if (Gbl_VerboseErrors && !PrematureEOF)
345             {
346                 SourceColumn = Enode->Column + Enode->FilenameLength + 6 + 2;
347                 ErrorColumn = ASL_ERROR_LEVEL_LENGTH + 5 + 2 + 1;
348 
349                 if ((MsgLength + ErrorColumn) < (SourceColumn - 1))
350                 {
351                     fprintf (OutputFile, "%*s%s",
352                         (int) ((SourceColumn - 1) - ErrorColumn),
353                         MainMessage, " ^ ");
354                 }
355                 else
356                 {
357                     fprintf (OutputFile, "%*s %s",
358                         (int) ((SourceColumn - ErrorColumn) + 1), "^",
359                         MainMessage);
360                 }
361             }
362             else
363             {
364                 fprintf (OutputFile, " %s", MainMessage);
365             }
366 
367             /* Print the extra info message if present */
368 
369             if (ExtraMessage)
370             {
371                 fprintf (OutputFile, " (%s)", ExtraMessage);
372             }
373 
374             if (PrematureEOF)
375             {
376                 fprintf (OutputFile, " and premature End-Of-File");
377             }
378 
379             fprintf (OutputFile, "\n");
380             if (Gbl_VerboseErrors)
381             {
382                 fprintf (OutputFile, "\n");
383             }
384         }
385         else
386         {
387             fprintf (OutputFile, " %s %s\n\n", MainMessage, ExtraMessage);
388         }
389     }
390 }
391 
392 
393 /*******************************************************************************
394  *
395  * FUNCTION:    AePrintErrorLog
396  *
397  * PARAMETERS:  FileId           - Where to output the error log
398  *
399  * RETURN:      None
400  *
401  * DESCRIPTION: Print the entire contents of the error log
402  *
403  ******************************************************************************/
404 
405 void
406 AePrintErrorLog (
407     UINT32                  FileId)
408 {
409     ASL_ERROR_MSG           *Enode = Gbl_ErrorLog;
410 
411 
412     /* Walk the error node list */
413 
414     while (Enode)
415     {
416         AePrintException (FileId, Enode, NULL);
417         Enode = Enode->Next;
418     }
419 }
420 
421 
422 /*******************************************************************************
423  *
424  * FUNCTION:    AslCommonError
425  *
426  * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
427  *              MessageId           - Index into global message buffer
428  *              CurrentLineNumber   - Actual file line number
429  *              LogicalLineNumber   - Cumulative line number
430  *              LogicalByteOffset   - Byte offset in source file
431  *              Column              - Column in current line
432  *              Filename            - source filename
433  *              ExtraMessage        - additional error message
434  *
435  * RETURN:      None
436  *
437  * DESCRIPTION: Create a new error node and add it to the error log
438  *
439  ******************************************************************************/
440 
441 void
442 AslCommonError (
443     UINT8                   Level,
444     UINT8                   MessageId,
445     UINT32                  CurrentLineNumber,
446     UINT32                  LogicalLineNumber,
447     UINT32                  LogicalByteOffset,
448     UINT32                  Column,
449     char                    *Filename,
450     char                    *ExtraMessage)
451 {
452     UINT32                  MessageSize;
453     char                    *MessageBuffer = NULL;
454     ASL_ERROR_MSG           *Enode;
455 
456 
457     Enode = UtLocalCalloc (sizeof (ASL_ERROR_MSG));
458 
459     if (ExtraMessage)
460     {
461         /* Allocate a buffer for the message and a new error node */
462 
463         MessageSize   = strlen (ExtraMessage) + 1;
464         MessageBuffer = UtLocalCalloc (MessageSize);
465 
466         /* Keep a copy of the extra message */
467 
468         ACPI_STRCPY (MessageBuffer, ExtraMessage);
469     }
470 
471     /* Initialize the error node */
472 
473     if (Filename)
474     {
475         Enode->Filename       = Filename;
476         Enode->FilenameLength = strlen (Filename);
477         if (Enode->FilenameLength < 6)
478         {
479             Enode->FilenameLength = 6;
480         }
481     }
482 
483     Enode->MessageId            = MessageId;
484     Enode->Level                = Level;
485     Enode->LineNumber           = CurrentLineNumber;
486     Enode->LogicalLineNumber    = LogicalLineNumber;
487     Enode->LogicalByteOffset    = LogicalByteOffset;
488     Enode->Column               = Column;
489     Enode->Message              = MessageBuffer;
490 
491     /* Add the new node to the error node list */
492 
493     AeAddToErrorLog (Enode);
494 
495     if (Gbl_DebugFlag)
496     {
497         /* stderr is a file, send error to it immediately */
498 
499         AePrintException (ASL_FILE_STDERR, Enode, NULL);
500     }
501 
502     Gbl_ExceptionCount[Level]++;
503     if (Gbl_ExceptionCount[ASL_ERROR] > ASL_MAX_ERROR_COUNT)
504     {
505         printf ("\nMaximum error count (%u) exceeded\n", ASL_MAX_ERROR_COUNT);
506 
507         Gbl_SourceLine = 0;
508         Gbl_NextError = Gbl_ErrorLog;
509         CmDoOutputFiles ();
510         CmCleanupAndExit ();
511         exit(1);
512     }
513 
514     return;
515 }
516 
517 
518 /*******************************************************************************
519  *
520  * FUNCTION:    AslError
521  *
522  * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
523  *              MessageId           - Index into global message buffer
524  *              Op                  - Parse node where error happened
525  *              ExtraMessage        - additional error message
526  *
527  * RETURN:      None
528  *
529  * DESCRIPTION: Main error reporting routine for the ASL compiler (all code
530  *              except the parser.)
531  *
532  ******************************************************************************/
533 
534 void
535 AslError (
536     UINT8                   Level,
537     UINT8                   MessageId,
538     ACPI_PARSE_OBJECT       *Op,
539     char                    *ExtraMessage)
540 {
541 
542     switch (Level)
543     {
544     case ASL_WARNING2:
545     case ASL_WARNING3:
546         if (Gbl_WarningLevel < Level)
547         {
548             return;
549         }
550         break;
551 
552     default:
553         break;
554     }
555 
556 
557     if (Op)
558     {
559         AslCommonError (Level, MessageId, Op->Asl.LineNumber,
560                         Op->Asl.LogicalLineNumber,
561                         Op->Asl.LogicalByteOffset,
562                         Op->Asl.Column,
563                         Op->Asl.Filename, ExtraMessage);
564     }
565     else
566     {
567         AslCommonError (Level, MessageId, 0,
568                         0, 0, 0, NULL, ExtraMessage);
569     }
570 }
571 
572 
573 /*******************************************************************************
574  *
575  * FUNCTION:    AslCoreSubsystemError
576  *
577  * PARAMETERS:  Op                  - Parse node where error happened
578  *              Status              - The ACPI CA Exception
579  *              ExtraMessage        - additional error message
580  *              Abort               - TRUE -> Abort compilation
581  *
582  * RETURN:      None
583  *
584  * DESCRIPTION: Error reporting routine for exceptions returned by the ACPI
585  *              CA core subsystem.
586  *
587  ******************************************************************************/
588 
589 void
590 AslCoreSubsystemError (
591     ACPI_PARSE_OBJECT       *Op,
592     ACPI_STATUS             Status,
593     char                    *ExtraMessage,
594     BOOLEAN                 Abort)
595 {
596 
597     sprintf (MsgBuffer, "%s %s", AcpiFormatException (Status), ExtraMessage);
598 
599     if (Op)
600     {
601         AslCommonError (ASL_ERROR, ASL_MSG_CORE_EXCEPTION, Op->Asl.LineNumber,
602                         Op->Asl.LogicalLineNumber,
603                         Op->Asl.LogicalByteOffset,
604                         Op->Asl.Column,
605                         Op->Asl.Filename, MsgBuffer);
606     }
607     else
608     {
609         AslCommonError (ASL_ERROR, ASL_MSG_CORE_EXCEPTION, 0,
610                         0, 0, 0, NULL, MsgBuffer);
611     }
612 
613     if (Abort)
614     {
615         AslAbort ();
616     }
617 }
618 
619 
620 /*******************************************************************************
621  *
622  * FUNCTION:    AslCompilererror
623  *
624  * PARAMETERS:  CompilerMessage         - Error message from the parser
625  *
626  * RETURN:      Status (0 for now)
627  *
628  * DESCRIPTION: Report an error situation discovered in a production
629  *              NOTE: don't change the name of this function, it is called
630  *              from the auto-generated parser.
631  *
632  ******************************************************************************/
633 
634 int
635 AslCompilererror (
636     const char              *CompilerMessage)
637 {
638 
639     AslCommonError (ASL_ERROR, ASL_MSG_SYNTAX, Gbl_CurrentLineNumber,
640         Gbl_LogicalLineNumber, Gbl_CurrentLineOffset,
641         Gbl_CurrentColumn, Gbl_Files[ASL_FILE_INPUT].Filename,
642         ACPI_CAST_PTR (char, CompilerMessage));
643 
644     return 0;
645 }
646 
647 
648