1 /******************************************************************************
2  *
3  * Module Name: asllisting - Listing file generation
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #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
96 LsDoListings (
97     void)
98 {
99 
100     if (Gbl_C_OutputFlag)
101     {
102         LsGenerateListing (ASL_FILE_C_SOURCE_OUTPUT);
103     }
104 
105     if (Gbl_ListingFlag)
106     {
107         LsGenerateListing (ASL_FILE_LISTING_OUTPUT);
108     }
109 
110     if (Gbl_AsmOutputFlag)
111     {
112         LsGenerateListing (ASL_FILE_ASM_SOURCE_OUTPUT);
113     }
114 
115     if (Gbl_C_IncludeOutputFlag)
116     {
117         LsGenerateListing (ASL_FILE_C_INCLUDE_OUTPUT);
118     }
119 
120     if (Gbl_AsmIncludeOutputFlag)
121     {
122         LsGenerateListing (ASL_FILE_ASM_INCLUDE_OUTPUT);
123     }
124 
125     if (Gbl_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
146 LsGenerateListing (
147     UINT32                  FileId)
148 {
149 
150     /* Start at the beginning of both the source and AML files */
151 
152     FlSeekFile (ASL_FILE_SOURCE_OUTPUT, 0);
153     FlSeekFile (ASL_FILE_AML_OUTPUT, 0);
154     Gbl_SourceLine = 0;
155     Gbl_CurrentHexColumn = 0;
156     LsPushNode (Gbl_Files[ASL_FILE_INPUT].Filename);
157 
158     if (FileId == ASL_FILE_C_OFFSET_OUTPUT)
159     {
160         Gbl_CurrentAmlOffset = 0;
161 
162         /* Offset table file has a special header and footer */
163 
164         LsDoOffsetTableHeader (FileId);
165 
166         TrWalkParseTree (Gbl_ParseTreeRoot, ASL_WALK_VISIT_DOWNWARD,
167             LsAmlOffsetWalk, NULL, (void *) ACPI_TO_POINTER (FileId));
168         LsDoOffsetTableFooter (FileId);
169         return;
170     }
171 
172     /* Process all parse nodes */
173 
174     TrWalkParseTree (Gbl_ParseTreeRoot, ASL_WALK_VISIT_DOWNWARD,
175         LsAmlListingWalk, NULL, (void *) ACPI_TO_POINTER (FileId));
176 
177     /* Final processing */
178 
179     LsFinishSourceListing (FileId);
180 }
181 
182 
183 /*******************************************************************************
184  *
185  * FUNCTION:    LsAmlListingWalk
186  *
187  * PARAMETERS:  ASL_WALK_CALLBACK
188  *
189  * RETURN:      Status
190  *
191  * DESCRIPTION: Process one node during a listing file generation.
192  *
193  ******************************************************************************/
194 
195 static ACPI_STATUS
196 LsAmlListingWalk (
197     ACPI_PARSE_OBJECT       *Op,
198     UINT32                  Level,
199     void                    *Context)
200 {
201     UINT8                   FileByte;
202     UINT32                  i;
203     UINT32                  FileId = (UINT32) ACPI_TO_INTEGER (Context);
204 
205 
206     LsWriteNodeToListing (Op, FileId);
207 
208     if (Op->Asl.CompileFlags & NODE_IS_RESOURCE_DATA)
209     {
210         /* Buffer is a resource template, don't dump the data all at once */
211 
212         return (AE_OK);
213     }
214 
215     if ((FileId == ASL_FILE_ASM_INCLUDE_OUTPUT) ||
216         (FileId == ASL_FILE_C_INCLUDE_OUTPUT))
217     {
218         return (AE_OK);
219     }
220 
221     /* Write the hex bytes to the listing file(s) (if requested) */
222 
223     for (i = 0; i < Op->Asl.FinalAmlLength; i++)
224     {
225         if (ACPI_FAILURE (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1)))
226         {
227             FlFileError (ASL_FILE_AML_OUTPUT, ASL_MSG_READ);
228             AslAbort ();
229         }
230 
231         LsWriteListingHexBytes (&FileByte, 1, FileId);
232     }
233 
234     return (AE_OK);
235 }
236 
237 
238 /*******************************************************************************
239  *
240  * FUNCTION:    LsDumpParseTree, LsTreeWriteWalk
241  *
242  * PARAMETERS:  None
243  *
244  * RETURN:      None
245  *
246  * DESCRIPTION: Dump entire parse tree, for compiler debug only
247  *
248  ******************************************************************************/
249 
250 void
251 LsDumpParseTree (
252     void)
253 {
254 
255     if (!Gbl_DebugFlag)
256     {
257         return;
258     }
259 
260     DbgPrint (ASL_TREE_OUTPUT, "\nOriginal parse tree from parser:\n\n");
261     DbgPrint (ASL_TREE_OUTPUT, ASL_PARSE_TREE_HEADER1);
262 
263     TrWalkParseTree (Gbl_ParseTreeRoot, ASL_WALK_VISIT_DOWNWARD,
264         LsTreeWriteWalk, NULL, NULL);
265 
266     DbgPrint (ASL_TREE_OUTPUT, ASL_PARSE_TREE_HEADER1);
267 }
268 
269 
270 static ACPI_STATUS
271 LsTreeWriteWalk (
272     ACPI_PARSE_OBJECT       *Op,
273     UINT32                  Level,
274     void                    *Context)
275 {
276 
277     /* Dump ParseOp name and possible value */
278 
279     switch (Op->Asl.ParseOpcode)
280     {
281         case PARSEOP_NAMESEG:
282         case PARSEOP_NAMESTRING:
283         case PARSEOP_METHODCALL:
284         case PARSEOP_STRING_LITERAL:
285 
286         UtDumpStringOp (Op, Level);
287         break;
288 
289     case PARSEOP_BYTECONST:
290 
291         UtDumpIntegerOp (Op, Level, 2);
292         break;
293 
294     case PARSEOP_WORDCONST:
295     case PARSEOP_PACKAGE_LENGTH:
296 
297         UtDumpIntegerOp (Op, Level, 4);
298         break;
299 
300     case PARSEOP_DWORDCONST:
301     case PARSEOP_EISAID:
302 
303         UtDumpIntegerOp (Op, Level, 8);
304         break;
305 
306     case PARSEOP_QWORDCONST:
307     case PARSEOP_INTEGER:
308     case PARSEOP_ONE:
309     case PARSEOP_ZERO:
310     case PARSEOP_ONES:
311 
312         UtDumpIntegerOp (Op, Level, 16);
313         break;
314 
315     case PARSEOP_INCLUDE:
316 
317         DbgPrint (ASL_TREE_OUTPUT,
318             "Open: %s\n", Op->Asl.Value.String);
319         return (AE_OK);
320 
321     case PARSEOP_INCLUDE_END:
322 
323         DbgPrint (ASL_TREE_OUTPUT,
324             "Close: %s\n", Op->Asl.Filename);
325         return (AE_OK);
326 
327     default:
328 
329         UtDumpBasicOp (Op, Level);
330         break;
331     }
332 
333     /* Dump the remaining data */
334 
335     DbgPrint (ASL_TREE_OUTPUT, ASL_PARSE_TREE_DEBUG1,
336         Op->Asl.ParseOpcode, Op->Asl.CompileFlags,
337         Op->Asl.LineNumber, Op->Asl.EndLine,
338         Op->Asl.LogicalLineNumber, Op->Asl.EndLogicalLine);
339 
340     TrPrintNodeCompileFlags (Op->Asl.CompileFlags);
341     DbgPrint (ASL_TREE_OUTPUT, "\n");
342     return (AE_OK);
343 }
344 
345 
346 /*******************************************************************************
347  *
348  * FUNCTION:    LsWriteNodeToListing
349  *
350  * PARAMETERS:  Op              - Parse node to write to the listing file.
351  *              FileId          - ID of current listing file
352  *
353  * RETURN:      None.
354  *
355  * DESCRIPTION: Write "a node" to the listing file. This means to
356  *              1) Write out all of the source text associated with the node
357  *              2) Write out all of the AML bytes associated with the node
358  *              3) Write any compiler exceptions associated with the node
359  *
360  ******************************************************************************/
361 
362 static void
363 LsWriteNodeToListing (
364     ACPI_PARSE_OBJECT       *Op,
365     UINT32                  FileId)
366 {
367     const ACPI_OPCODE_INFO  *OpInfo;
368     UINT32                  OpClass;
369     char                    *Pathname;
370     UINT32                  Length;
371     UINT32                  i;
372 
373 
374     OpInfo  = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
375     OpClass = OpInfo->Class;
376 
377     /* TBD: clean this up with a single flag that says:
378      * I start a named output block
379      */
380     if (FileId == ASL_FILE_C_SOURCE_OUTPUT)
381     {
382         switch (Op->Asl.ParseOpcode)
383         {
384         case PARSEOP_DEFINITION_BLOCK:
385         case PARSEOP_METHODCALL:
386         case PARSEOP_INCLUDE:
387         case PARSEOP_INCLUDE_END:
388         case PARSEOP_DEFAULT_ARG:
389 
390             break;
391 
392         default:
393 
394             switch (OpClass)
395             {
396             case AML_CLASS_NAMED_OBJECT:
397 
398                 switch (Op->Asl.AmlOpcode)
399                 {
400                 case AML_SCOPE_OP:
401                 case AML_ALIAS_OP:
402 
403                     break;
404 
405                 default:
406 
407                     if (Op->Asl.ExternalName)
408                     {
409                         LsFlushListingBuffer (FileId);
410                         FlPrintFile (FileId, "    };\n");
411                     }
412                     break;
413                 }
414                 break;
415 
416             default:
417 
418                 /* Don't care about other objects */
419 
420                 break;
421             }
422             break;
423         }
424     }
425 
426     /* These cases do not have a corresponding AML opcode */
427 
428     switch (Op->Asl.ParseOpcode)
429     {
430     case PARSEOP_DEFINITION_BLOCK:
431 
432         /* Always start a definition block at AML offset zero */
433 
434         Gbl_CurrentAmlOffset = 0;
435         LsWriteSourceLines (Op->Asl.EndLine, Op->Asl.EndLogicalLine, FileId);
436 
437         /* Use the table Signature and TableId to build a unique name */
438 
439         switch (FileId)
440         {
441         case ASL_FILE_ASM_SOURCE_OUTPUT:
442 
443             FlPrintFile (FileId,
444                 "%s_%s_Header \\\n",
445                 Gbl_TableSignature, Gbl_TableId);
446             break;
447 
448         case ASL_FILE_C_SOURCE_OUTPUT:
449 
450             FlPrintFile (FileId,
451                 "    unsigned char    %s_%s_Header [] =\n    {\n",
452                 Gbl_TableSignature, Gbl_TableId);
453             break;
454 
455         case ASL_FILE_ASM_INCLUDE_OUTPUT:
456 
457             FlPrintFile (FileId,
458                 "extrn %s_%s_Header : byte\n",
459                 Gbl_TableSignature, Gbl_TableId);
460             break;
461 
462         case ASL_FILE_C_INCLUDE_OUTPUT:
463 
464             FlPrintFile (FileId,
465                 "extern unsigned char    %s_%s_Header [];\n",
466                 Gbl_TableSignature, Gbl_TableId);
467             break;
468 
469         default:
470             break;
471         }
472 
473         return;
474 
475 
476     case PARSEOP_METHODCALL:
477 
478         LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.LogicalLineNumber,
479             FileId);
480         return;
481 
482 
483     case PARSEOP_INCLUDE:
484 
485         /* Flush everything up to and including the include source line */
486 
487         LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.LogicalLineNumber,
488             FileId);
489 
490         /* Create a new listing node and push it */
491 
492         LsPushNode (Op->Asl.Value.String);
493         return;
494 
495 
496     case PARSEOP_INCLUDE_END:
497 
498         /* Flush out the rest of the include file */
499 
500         LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.LogicalLineNumber,
501             FileId);
502 
503         /* Pop off this listing node and go back to the parent file */
504 
505         (void) LsPopNode ();
506         return;
507 
508 
509     case PARSEOP_DEFAULT_ARG:
510 
511         if (Op->Asl.CompileFlags & NODE_IS_RESOURCE_DESC)
512         {
513             LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.EndLogicalLine,
514                 FileId);
515         }
516         return;
517 
518 
519     default:
520 
521         /* All other opcodes have an AML opcode */
522 
523         break;
524     }
525 
526     /*
527      * Otherwise, we look at the AML opcode because we can
528      * switch on the opcode type, getting an entire class
529      * at once
530      */
531     switch (OpClass)
532     {
533     case AML_CLASS_ARGUMENT:       /* argument type only */
534     case AML_CLASS_INTERNAL:
535 
536         break;
537 
538     case AML_CLASS_NAMED_OBJECT:
539 
540         switch (Op->Asl.AmlOpcode)
541         {
542         case AML_FIELD_OP:
543         case AML_INDEX_FIELD_OP:
544         case AML_BANK_FIELD_OP:
545             /*
546              * For fields, we want to dump all the AML after the
547              * entire definition
548              */
549             LsWriteSourceLines (Op->Asl.EndLine, Op->Asl.EndLogicalLine,
550                 FileId);
551             break;
552 
553         case AML_NAME_OP:
554 
555             if (Op->Asl.CompileFlags & NODE_IS_RESOURCE_DESC)
556             {
557                 LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.LogicalLineNumber,
558                     FileId);
559             }
560             else
561             {
562                 /*
563                  * For fields, we want to dump all the AML after the
564                  * entire definition
565                  */
566                 LsWriteSourceLines (Op->Asl.EndLine, Op->Asl.EndLogicalLine,
567                     FileId);
568             }
569             break;
570 
571         default:
572 
573             LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.LogicalLineNumber,
574                 FileId);
575             break;
576         }
577 
578         switch (Op->Asl.AmlOpcode)
579         {
580         case AML_SCOPE_OP:
581         case AML_ALIAS_OP:
582 
583             /* These opcodes do not declare a new object, ignore them */
584 
585             break;
586 
587         default:
588 
589             /* All other named object opcodes come here */
590 
591             switch (FileId)
592             {
593             case ASL_FILE_ASM_SOURCE_OUTPUT:
594             case ASL_FILE_C_SOURCE_OUTPUT:
595             case ASL_FILE_ASM_INCLUDE_OUTPUT:
596             case ASL_FILE_C_INCLUDE_OUTPUT:
597                 /*
598                  * For named objects, we will create a valid symbol so that the
599                  * AML code can be referenced from C or ASM
600                  */
601                 if (Op->Asl.ExternalName)
602                 {
603                     /* Get the full pathname associated with this node */
604 
605                     Pathname = AcpiNsGetExternalPathname (Op->Asl.Node);
606                     Length = strlen (Pathname);
607                     if (Length >= 4)
608                     {
609                         /* Convert all dots in the path to underscores */
610 
611                         for (i = 0; i < Length; i++)
612                         {
613                             if (Pathname[i] == '.')
614                             {
615                                 Pathname[i] = '_';
616                             }
617                         }
618 
619                         /* Create the appropriate symbol in the output file */
620 
621                         switch (FileId)
622                         {
623                         case ASL_FILE_ASM_SOURCE_OUTPUT:
624 
625                             FlPrintFile (FileId,
626                                 "%s_%s_%s  \\\n",
627                                 Gbl_TableSignature, Gbl_TableId, &Pathname[1]);
628                             break;
629 
630                         case ASL_FILE_C_SOURCE_OUTPUT:
631 
632                             FlPrintFile (FileId,
633                                 "    unsigned char    %s_%s_%s [] =\n    {\n",
634                                 Gbl_TableSignature, Gbl_TableId, &Pathname[1]);
635                             break;
636 
637                         case ASL_FILE_ASM_INCLUDE_OUTPUT:
638 
639                             FlPrintFile (FileId,
640                                 "extrn %s_%s_%s : byte\n",
641                                 Gbl_TableSignature, Gbl_TableId, &Pathname[1]);
642                             break;
643 
644                         case ASL_FILE_C_INCLUDE_OUTPUT:
645 
646                             FlPrintFile (FileId,
647                                 "extern unsigned char    %s_%s_%s [];\n",
648                                 Gbl_TableSignature, Gbl_TableId, &Pathname[1]);
649                             break;
650 
651                         default:
652                             break;
653                         }
654                     }
655 
656                     ACPI_FREE (Pathname);
657                 }
658                 break;
659 
660             default:
661 
662                 /* Nothing to do for listing file */
663 
664                 break;
665             }
666         }
667         break;
668 
669     case AML_CLASS_EXECUTE:
670     case AML_CLASS_CREATE:
671     default:
672 
673         if ((Op->Asl.ParseOpcode == PARSEOP_BUFFER) &&
674             (Op->Asl.CompileFlags & NODE_IS_RESOURCE_DESC))
675         {
676             return;
677         }
678 
679         LsWriteSourceLines (Op->Asl.LineNumber, Op->Asl.LogicalLineNumber,
680             FileId);
681         break;
682 
683     case AML_CLASS_UNKNOWN:
684 
685         break;
686     }
687 }
688 
689 
690 /*******************************************************************************
691  *
692  * FUNCTION:    LsFinishSourceListing
693  *
694  * PARAMETERS:  FileId          - ID of current listing file.
695  *
696  * RETURN:      None
697  *
698  * DESCRIPTION: Cleanup routine for the listing file. Flush the hex AML
699  *              listing buffer, and flush out any remaining lines in the
700  *              source input file.
701  *
702  ******************************************************************************/
703 
704 static void
705 LsFinishSourceListing (
706     UINT32                  FileId)
707 {
708 
709     if ((FileId == ASL_FILE_ASM_INCLUDE_OUTPUT) ||
710         (FileId == ASL_FILE_C_INCLUDE_OUTPUT))
711     {
712         return;
713     }
714 
715     LsFlushListingBuffer (FileId);
716     Gbl_CurrentAmlOffset = 0;
717 
718     /* Flush any remaining text in the source file */
719 
720     if (FileId == ASL_FILE_C_SOURCE_OUTPUT)
721     {
722         FlPrintFile (FileId, "    /*\n");
723     }
724 
725     while (LsWriteOneSourceLine (FileId))
726     { ; }
727 
728     if (FileId == ASL_FILE_C_SOURCE_OUTPUT)
729     {
730         FlPrintFile (FileId, "\n     */\n    };\n");
731     }
732 
733     FlPrintFile (FileId, "\n");
734 
735     if (FileId == ASL_FILE_LISTING_OUTPUT)
736     {
737         /* Print a summary of the compile exceptions */
738 
739         FlPrintFile (FileId, "\n\nSummary of errors and warnings\n\n");
740         AePrintErrorLog (FileId);
741         FlPrintFile (FileId, "\n");
742         UtDisplaySummary (FileId);
743         FlPrintFile (FileId, "\n");
744     }
745 }
746