xref: /netbsd-src/sys/external/bsd/acpica/dist/compiler/asllisting.c (revision 046a29855e04359424fd074e8313af6b6be8cfb6)
1 /******************************************************************************
2  *
3  * Module Name: asllisting - Listing file generation
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2023, 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 MERCHANTABILITY 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 #include "aslcompiler.h"
45 #include "aslcompiler.y.h"
46 #include "amlcode.h"
47 #include "acparser.h"
48 #include "acnamesp.h"
49 
50 
51 #define _COMPONENT          ACPI_COMPILER
52         ACPI_MODULE_NAME    ("asllisting")
53 
54 
55 /* Local prototypes */
56 
57 static void
58 LsGenerateListing (
59     UINT32                  FileId);
60 
61 static ACPI_STATUS
62 LsAmlListingWalk (
63     ACPI_PARSE_OBJECT       *Op,
64     UINT32                  Level,
65     void                    *Context);
66 
67 static ACPI_STATUS
68 LsTreeWriteWalk (
69     ACPI_PARSE_OBJECT       *Op,
70     UINT32                  Level,
71     void                    *Context);
72 
73 static void
74 LsWriteNodeToListing (
75     ACPI_PARSE_OBJECT       *Op,
76     UINT32                  FileId);
77 
78 static void
79 LsFinishSourceListing (
80     UINT32                  FileId);
81 
82 
83 /*******************************************************************************
84  *
85  * FUNCTION:    LsDoListings
86  *
87  * PARAMETERS:  None. Examines the various output file global flags.
88  *
89  * RETURN:      None
90  *
91  * DESCRIPTION: Generate all requested listing files.
92  *
93  ******************************************************************************/
94 
95 void
LsDoListings(void)96 LsDoListings (
97     void)
98 {
99 
100     if (AslGbl_C_OutputFlag)
101     {
102         LsGenerateListing (ASL_FILE_C_SOURCE_OUTPUT);
103     }
104 
105     if (AslGbl_ListingFlag)
106     {
107         LsGenerateListing (ASL_FILE_LISTING_OUTPUT);
108     }
109 
110     if (AslGbl_AsmOutputFlag)
111     {
112         LsGenerateListing (ASL_FILE_ASM_SOURCE_OUTPUT);
113     }
114 
115     if (AslGbl_C_IncludeOutputFlag)
116     {
117         LsGenerateListing (ASL_FILE_C_INCLUDE_OUTPUT);
118     }
119 
120     if (AslGbl_AsmIncludeOutputFlag)
121     {
122         LsGenerateListing (ASL_FILE_ASM_INCLUDE_OUTPUT);
123     }
124 
125     if (AslGbl_C_OffsetTableFlag)
126     {
127         LsGenerateListing (ASL_FILE_C_OFFSET_OUTPUT);
128     }
129 }
130 
131 
132 /*******************************************************************************
133  *
134  * FUNCTION:    LsGenerateListing
135  *
136  * PARAMETERS:  FileId      - ID of listing file
137  *
138  * RETURN:      None
139  *
140  * DESCRIPTION: Generate a listing file. This can be one of the several types
141  *              of "listings" supported.
142  *
143  ******************************************************************************/
144 
145 static void
LsGenerateListing(UINT32 FileId)146 LsGenerateListing (
147     UINT32                  FileId)
148 {
149     UINT32                  WalkMode = ASL_WALK_VISIT_DOWNWARD | ASL_WALK_VISIT_DB_SEPARATELY;
150 
151     /* Start at the beginning of both the source and AML files */
152 
153     FlSeekFile (ASL_FILE_SOURCE_OUTPUT, 0);
154     FlSeekFile (ASL_FILE_AML_OUTPUT, 0);
155     AslGbl_SourceLine = 0;
156     AslGbl_CurrentHexColumn = 0;
157     LsPushNode (AslGbl_Files[ASL_FILE_INPUT].Filename);
158 
159     if (FileId == ASL_FILE_C_OFFSET_OUTPUT)
160     {
161         AslGbl_CurrentAmlOffset = 0;
162 
163         /* Offset table file has a special header and footer */
164 
165         LsDoOffsetTableHeader (FileId);
166 
167         TrWalkParseTree (AslGbl_CurrentDB, WalkMode,
168             LsAmlOffsetWalk, NULL, (void *) ACPI_TO_POINTER (FileId));
169         LsDoOffsetTableFooter (FileId);
170         return;
171     }
172 
173     /* Process all parse nodes */
174 
175     TrWalkParseTree (AslGbl_CurrentDB, WalkMode,
176         LsAmlListingWalk, NULL, (void *) ACPI_TO_POINTER (FileId));
177 
178     /* Final processing */
179 
180     LsFinishSourceListing (FileId);
181 }
182 
183 
184 /*******************************************************************************
185  *
186  * FUNCTION:    LsAmlListingWalk
187  *
188  * PARAMETERS:  ASL_WALK_CALLBACK
189  *
190  * RETURN:      Status
191  *
192  * DESCRIPTION: Process one node during a listing file generation.
193  *
194  ******************************************************************************/
195 
196 static ACPI_STATUS
LsAmlListingWalk(ACPI_PARSE_OBJECT * Op,UINT32 Level,void * Context)197 LsAmlListingWalk (
198     ACPI_PARSE_OBJECT       *Op,
199     UINT32                  Level,
200     void                    *Context)
201 {
202     UINT8                   FileByte;
203     UINT32                  i;
204     UINT32                  FileId = (UINT32) ACPI_TO_INTEGER (Context);
205 
206 
207     LsWriteNodeToListing (Op, FileId);
208 
209     if (Op->Asl.CompileFlags & OP_IS_RESOURCE_DATA)
210     {
211         /* Buffer is a resource template, don't dump the data all at once */
212 
213         return (AE_OK);
214     }
215 
216     if ((FileId == ASL_FILE_ASM_INCLUDE_OUTPUT) ||
217         (FileId == ASL_FILE_C_INCLUDE_OUTPUT))
218     {
219         return (AE_OK);
220     }
221 
222     /* Write the hex bytes to the listing file(s) (if requested) */
223 
224     for (i = 0; i < Op->Asl.FinalAmlLength; i++)
225     {
226         if (ACPI_FAILURE (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1)))
227         {
228             FlFileError (ASL_FILE_AML_OUTPUT, ASL_MSG_READ);
229             AslAbort ();
230         }
231 
232         LsWriteListingHexBytes (&FileByte, 1, FileId);
233     }
234 
235     return (AE_OK);
236 }
237 
238 
239 /*******************************************************************************
240  *
241  * FUNCTION:    LsDumpParseTree, LsTreeWriteWalk
242  *
243  * PARAMETERS:  None
244  *
245  * RETURN:      None
246  *
247  * DESCRIPTION: Dump entire parse tree, for compiler debug only
248  *
249  ******************************************************************************/
250 
251 void
LsDumpParseTree(void)252 LsDumpParseTree (
253     void)
254 {
255 
256     if (!AslGbl_DebugFlag)
257     {
258         return;
259     }
260 
261     DbgPrint (ASL_TREE_OUTPUT, "\nOriginal parse tree from parser:\n\n");
262     DbgPrint (ASL_TREE_OUTPUT, ASL_PARSE_TREE_HEADER1);
263 
264     TrWalkParseTree (AslGbl_ParseTreeRoot, ASL_WALK_VISIT_DOWNWARD,
265         LsTreeWriteWalk, NULL, NULL);
266 
267     DbgPrint (ASL_TREE_OUTPUT, ASL_PARSE_TREE_HEADER1);
268 }
269 
270 
271 static ACPI_STATUS
LsTreeWriteWalk(ACPI_PARSE_OBJECT * Op,UINT32 Level,void * Context)272 LsTreeWriteWalk (
273     ACPI_PARSE_OBJECT       *Op,
274     UINT32                  Level,
275     void                    *Context)
276 {
277 
278     /* Dump ParseOp name and possible value */
279 
280     switch (Op->Asl.ParseOpcode)
281     {
282         case PARSEOP_NAMESEG:
283         case PARSEOP_NAMESTRING:
284         case PARSEOP_METHODCALL:
285         case PARSEOP_STRING_LITERAL:
286 
287         UtDumpStringOp (Op, Level);
288         break;
289 
290     case PARSEOP_BYTECONST:
291 
292         UtDumpIntegerOp (Op, Level, 2);
293         break;
294 
295     case PARSEOP_WORDCONST:
296     case PARSEOP_PACKAGE_LENGTH:
297 
298         UtDumpIntegerOp (Op, Level, 4);
299         break;
300 
301     case PARSEOP_DWORDCONST:
302     case PARSEOP_EISAID:
303 
304         UtDumpIntegerOp (Op, Level, 8);
305         break;
306 
307     case PARSEOP_QWORDCONST:
308     case PARSEOP_INTEGER:
309     case PARSEOP_ONE:
310     case PARSEOP_ZERO:
311     case PARSEOP_ONES:
312 
313         UtDumpIntegerOp (Op, Level, 16);
314         break;
315 
316     case PARSEOP_INCLUDE:
317 
318         DbgPrint (ASL_TREE_OUTPUT,
319             "Open: %s\n", Op->Asl.Value.String);
320         return (AE_OK);
321 
322     case PARSEOP_INCLUDE_END:
323 
324         DbgPrint (ASL_TREE_OUTPUT,
325             "Close: %s\n", Op->Asl.Filename);
326         return (AE_OK);
327 
328     default:
329 
330         UtDumpBasicOp (Op, Level);
331         break;
332     }
333 
334     /* Dump the remaining data */
335 
336     DbgPrint (ASL_TREE_OUTPUT, ASL_PARSE_TREE_DEBUG1,
337         Op->Asl.ParseOpcode, Op->Asl.CompileFlags,
338         Op->Asl.LineNumber, Op->Asl.EndLine,
339         Op->Asl.LogicalLineNumber, Op->Asl.EndLogicalLine);
340 
341     TrPrintOpFlags (Op->Asl.CompileFlags, ASL_TREE_OUTPUT);
342     DbgPrint (ASL_TREE_OUTPUT, "\n");
343     return (AE_OK);
344 }
345 
346 
347 /*******************************************************************************
348  *
349  * FUNCTION:    LsWriteNodeToListing
350  *
351  * PARAMETERS:  Op              - Parse node to write to the listing file.
352  *              FileId          - ID of current listing file
353  *
354  * RETURN:      None.
355  *
356  * DESCRIPTION: Write "a node" to the listing file. This means to
357  *              1) Write out all of the source text associated with the node
358  *              2) Write out all of the AML bytes associated with the node
359  *              3) Write any compiler exceptions associated with the node
360  *
361  ******************************************************************************/
362 
363 static void
LsWriteNodeToListing(ACPI_PARSE_OBJECT * Op,UINT32 FileId)364 LsWriteNodeToListing (
365     ACPI_PARSE_OBJECT       *Op,
366     UINT32                  FileId)
367 {
368     const ACPI_OPCODE_INFO  *OpInfo;
369     UINT32                  OpClass;
370     char                    *Pathname;
371     UINT32                  Length;
372     UINT32                  i;
373 
374 
375     OpInfo  = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
376     OpClass = OpInfo->Class;
377 
378     /* TBD: clean this up with a single flag that says:
379      * I start a named output block
380      */
381     if (FileId == ASL_FILE_C_SOURCE_OUTPUT)
382     {
383         switch (Op->Asl.ParseOpcode)
384         {
385         case PARSEOP_DEFINITION_BLOCK:
386         case PARSEOP_METHODCALL:
387         case PARSEOP_INCLUDE:
388         case PARSEOP_INCLUDE_END:
389         case PARSEOP_DEFAULT_ARG:
390 
391             break;
392 
393         default:
394 
395             switch (OpClass)
396             {
397             case AML_CLASS_NAMED_OBJECT:
398 
399                 switch (Op->Asl.AmlOpcode)
400                 {
401                 case AML_SCOPE_OP:
402                 case AML_ALIAS_OP:
403 
404                     break;
405 
406                 default:
407 
408                     if (Op->Asl.ExternalName)
409                     {
410                         LsFlushListingBuffer (FileId);
411                         FlPrintFile (FileId, "    };\n");
412                     }
413                     break;
414                 }
415                 break;
416 
417             default:
418 
419                 /* Don't care about other objects */
420 
421                 break;
422             }
423             break;
424         }
425     }
426 
427     /* These cases do not have a corresponding AML opcode */
428 
429     switch (Op->Asl.ParseOpcode)
430     {
431     case PARSEOP_DEFINITION_BLOCK:
432 
433         /* Always start a definition block at AML offset zero */
434 
435         AslGbl_CurrentAmlOffset = 0;
436         LsWriteSourceLines (Op->Asl.EndLine, Op->Asl.EndLogicalLine, FileId);
437 
438         /* Use the table Signature and TableId to build a unique name */
439 
440         switch (FileId)
441         {
442         case ASL_FILE_ASM_SOURCE_OUTPUT:
443 
444             FlPrintFile (FileId,
445                 "%s_%s_Header \\\n",
446                 AslGbl_TableSignature, AslGbl_TableId);
447             break;
448 
449         case ASL_FILE_C_SOURCE_OUTPUT:
450 
451             FlPrintFile (FileId,
452                 "    unsigned char    %s_%s_Header [] =\n    {\n",
453                 AslGbl_TableSignature, AslGbl_TableId);
454             break;
455 
456         case ASL_FILE_ASM_INCLUDE_OUTPUT:
457 
458             FlPrintFile (FileId,
459                 "extrn %s_%s_Header : byte\n",
460                 AslGbl_TableSignature, AslGbl_TableId);
461             break;
462 
463         case ASL_FILE_C_INCLUDE_OUTPUT:
464 
465             FlPrintFile (FileId,
466                 "extern unsigned char    %s_%s_Header [];\n",
467                 AslGbl_TableSignature, AslGbl_TableId);
468             break;
469 
470         default:
471             break;
472         }
473 
474         return;
475 
476 
477     case PARSEOP_METHODCALL:
478 
479         LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.LogicalLineNumber,
480             FileId);
481         return;
482 
483 
484     case PARSEOP_INCLUDE:
485 
486         /* Flush everything up to and including the include source line */
487 
488         LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.LogicalLineNumber,
489             FileId);
490 
491         /* Create a new listing node and push it */
492 
493         LsPushNode (Op->Asl.Value.String);
494         return;
495 
496 
497     case PARSEOP_INCLUDE_END:
498 
499         /* Flush out the rest of the include file */
500 
501         LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.LogicalLineNumber,
502             FileId);
503 
504         /* Pop off this listing node and go back to the parent file */
505 
506         (void) LsPopNode ();
507         return;
508 
509 
510     case PARSEOP_DEFAULT_ARG:
511 
512         if (Op->Asl.CompileFlags & OP_IS_RESOURCE_DESC)
513         {
514             LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.EndLogicalLine,
515                 FileId);
516         }
517         return;
518 
519 
520     default:
521 
522         /* All other opcodes have an AML opcode */
523 
524         break;
525     }
526 
527     /*
528      * Otherwise, we look at the AML opcode because we can
529      * switch on the opcode type, getting an entire class
530      * at once
531      */
532     switch (OpClass)
533     {
534     case AML_CLASS_ARGUMENT:       /* argument type only */
535     case AML_CLASS_INTERNAL:
536 
537         break;
538 
539     case AML_CLASS_NAMED_OBJECT:
540 
541         switch (Op->Asl.AmlOpcode)
542         {
543         case AML_FIELD_OP:
544         case AML_INDEX_FIELD_OP:
545         case AML_BANK_FIELD_OP:
546             /*
547              * For fields, we want to dump all the AML after the
548              * entire definition
549              */
550             LsWriteSourceLines (Op->Asl.EndLine, Op->Asl.EndLogicalLine,
551                 FileId);
552             break;
553 
554         case AML_NAME_OP:
555 
556             if (Op->Asl.CompileFlags & OP_IS_RESOURCE_DESC)
557             {
558                 LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.LogicalLineNumber,
559                     FileId);
560             }
561             else
562             {
563                 /*
564                  * For fields, we want to dump all the AML after the
565                  * entire definition
566                  */
567                 LsWriteSourceLines (Op->Asl.EndLine, Op->Asl.EndLogicalLine,
568                     FileId);
569             }
570             break;
571 
572         default:
573 
574             LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.LogicalLineNumber,
575                 FileId);
576             break;
577         }
578 
579         switch (Op->Asl.AmlOpcode)
580         {
581         case AML_SCOPE_OP:
582         case AML_ALIAS_OP:
583 
584             /* These opcodes do not declare a new object, ignore them */
585 
586             break;
587 
588         default:
589 
590             /* All other named object opcodes come here */
591 
592             switch (FileId)
593             {
594             case ASL_FILE_ASM_SOURCE_OUTPUT:
595             case ASL_FILE_C_SOURCE_OUTPUT:
596             case ASL_FILE_ASM_INCLUDE_OUTPUT:
597             case ASL_FILE_C_INCLUDE_OUTPUT:
598                 /*
599                  * For named objects, we will create a valid symbol so that the
600                  * AML code can be referenced from C or ASM
601                  */
602                 if (Op->Asl.ExternalName)
603                 {
604                     /* Get the full pathname associated with this node */
605 
606                     Pathname = AcpiNsGetExternalPathname (Op->Asl.Node);
607                     Length = strlen (Pathname);
608                     if (Length >= 4)
609                     {
610                         /* Convert all dots in the path to underscores */
611 
612                         for (i = 0; i < Length; i++)
613                         {
614                             if (Pathname[i] == '.')
615                             {
616                                 Pathname[i] = '_';
617                             }
618                         }
619 
620                         /* Create the appropriate symbol in the output file */
621 
622                         switch (FileId)
623                         {
624                         case ASL_FILE_ASM_SOURCE_OUTPUT:
625 
626                             FlPrintFile (FileId,
627                                 "%s_%s_%s  \\\n",
628                                 AslGbl_TableSignature, AslGbl_TableId, &Pathname[1]);
629                             break;
630 
631                         case ASL_FILE_C_SOURCE_OUTPUT:
632 
633                             FlPrintFile (FileId,
634                                 "    unsigned char    %s_%s_%s [] =\n    {\n",
635                                 AslGbl_TableSignature, AslGbl_TableId, &Pathname[1]);
636                             break;
637 
638                         case ASL_FILE_ASM_INCLUDE_OUTPUT:
639 
640                             FlPrintFile (FileId,
641                                 "extrn %s_%s_%s : byte\n",
642                                 AslGbl_TableSignature, AslGbl_TableId, &Pathname[1]);
643                             break;
644 
645                         case ASL_FILE_C_INCLUDE_OUTPUT:
646 
647                             FlPrintFile (FileId,
648                                 "extern unsigned char    %s_%s_%s [];\n",
649                                 AslGbl_TableSignature, AslGbl_TableId, &Pathname[1]);
650                             break;
651 
652                         default:
653                             break;
654                         }
655                     }
656 
657                     ACPI_FREE (Pathname);
658                 }
659                 break;
660 
661             default:
662 
663                 /* Nothing to do for listing file */
664 
665                 break;
666             }
667         }
668         break;
669 
670     case AML_CLASS_EXECUTE:
671     case AML_CLASS_CREATE:
672     default:
673 
674         if ((Op->Asl.ParseOpcode == PARSEOP_BUFFER) &&
675             (Op->Asl.CompileFlags & OP_IS_RESOURCE_DESC))
676         {
677             return;
678         }
679 
680         LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.LogicalLineNumber,
681             FileId);
682         break;
683 
684     case AML_CLASS_UNKNOWN:
685 
686         break;
687     }
688 }
689 
690 
691 /*******************************************************************************
692  *
693  * FUNCTION:    LsFinishSourceListing
694  *
695  * PARAMETERS:  FileId          - ID of current listing file.
696  *
697  * RETURN:      None
698  *
699  * DESCRIPTION: Cleanup routine for the listing file. Flush the hex AML
700  *              listing buffer, and flush out any remaining lines in the
701  *              source input file.
702  *
703  ******************************************************************************/
704 
705 static void
LsFinishSourceListing(UINT32 FileId)706 LsFinishSourceListing (
707     UINT32                  FileId)
708 {
709 
710     if ((FileId == ASL_FILE_ASM_INCLUDE_OUTPUT) ||
711         (FileId == ASL_FILE_C_INCLUDE_OUTPUT))
712     {
713         return;
714     }
715 
716     LsFlushListingBuffer (FileId);
717     AslGbl_CurrentAmlOffset = 0;
718 
719     /* Flush any remaining text in the source file */
720 
721     if (FileId == ASL_FILE_C_SOURCE_OUTPUT)
722     {
723         FlPrintFile (FileId, "    /*\n");
724     }
725 
726     while (LsWriteOneSourceLine (FileId))
727     { ; }
728 
729     if (FileId == ASL_FILE_C_SOURCE_OUTPUT)
730     {
731         FlPrintFile (FileId, "\n     */\n    };\n");
732     }
733 
734     FlPrintFile (FileId, "\n");
735 
736     if (FileId == ASL_FILE_LISTING_OUTPUT)
737     {
738         /* Print a summary of the compile exceptions */
739 
740         FlPrintFile (FileId, "\n\nSummary of errors and warnings\n\n");
741         AePrintErrorLog (FileId);
742         FlPrintFile (FileId, "\n");
743         UtDisplayOneSummary (FileId, TRUE);
744         FlPrintFile (FileId, "\n");
745     }
746 }
747