1 /******************************************************************************
2  *
3  * Module Name: adisasm - Application-level disassembler routines
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2018, 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 "amlcode.h"
46 #include "acdisasm.h"
47 #include "acdispat.h"
48 #include "acnamesp.h"
49 #include "acparser.h"
50 #include "acapps.h"
51 
52 
53 #define _COMPONENT          ACPI_TOOLS
54         ACPI_MODULE_NAME    ("adisasm")
55 
56 /* Local prototypes */
57 
58 static ACPI_STATUS
59 AdDoExternalFileList (
60     char                    *Filename);
61 
62 static ACPI_STATUS
63 AdDisassembleOneTable (
64     ACPI_TABLE_HEADER       *Table,
65     FILE                    *File,
66     char                    *Filename,
67     char                    *DisasmFilename);
68 
69 static ACPI_STATUS
70 AdReparseOneTable (
71     ACPI_TABLE_HEADER       *Table,
72     FILE                    *File,
73     ACPI_OWNER_ID           OwnerId);
74 
75 
76 ACPI_TABLE_DESC             LocalTables[1];
77 ACPI_PARSE_OBJECT           *AcpiGbl_ParseOpRoot;
78 
79 
80 /* Stubs for everything except ASL compiler */
81 
82 #ifndef ACPI_ASL_COMPILER
83 BOOLEAN
84 AcpiDsIsResultUsed (
85     ACPI_PARSE_OBJECT       *Op,
86     ACPI_WALK_STATE         *WalkState)
87 {
88     return (TRUE);
89 }
90 
91 ACPI_STATUS
92 AcpiDsMethodError (
93     ACPI_STATUS             Status,
94     ACPI_WALK_STATE         *WalkState)
95 {
96     return (Status);
97 }
98 #endif
99 
100 
101 /*******************************************************************************
102  *
103  * FUNCTION:    AdInitialize
104  *
105  * PARAMETERS:  None
106  *
107  * RETURN:      Status
108  *
109  * DESCRIPTION: ACPICA and local initialization
110  *
111  ******************************************************************************/
112 
113 ACPI_STATUS
114 AdInitialize (
115     void)
116 {
117     ACPI_STATUS             Status;
118 
119 
120     /* ACPICA subsystem initialization */
121 
122     Status = AcpiOsInitialize ();
123     if (ACPI_FAILURE (Status))
124     {
125         fprintf (stderr, "Could not initialize ACPICA subsystem: %s\n",
126             AcpiFormatException (Status));
127 
128         return (Status);
129     }
130 
131     Status = AcpiUtInitGlobals ();
132     if (ACPI_FAILURE (Status))
133     {
134         fprintf (stderr, "Could not initialize ACPICA globals: %s\n",
135             AcpiFormatException (Status));
136 
137         return (Status);
138     }
139 
140     Status = AcpiUtMutexInitialize ();
141     if (ACPI_FAILURE (Status))
142     {
143         fprintf (stderr, "Could not initialize ACPICA mutex objects: %s\n",
144             AcpiFormatException (Status));
145 
146         return (Status);
147     }
148 
149     Status = AcpiNsRootInitialize ();
150     if (ACPI_FAILURE (Status))
151     {
152         fprintf (stderr, "Could not initialize ACPICA namespace: %s\n",
153             AcpiFormatException (Status));
154 
155         return (Status);
156     }
157 
158     /* Setup the Table Manager (cheat - there is no RSDT) */
159 
160     AcpiGbl_RootTableList.MaxTableCount = 1;
161     AcpiGbl_RootTableList.CurrentTableCount = 0;
162     AcpiGbl_RootTableList.Tables = LocalTables;
163 
164     return (AE_OK);
165 }
166 
167 
168 /******************************************************************************
169  *
170  * FUNCTION:    AdAmlDisassemble
171  *
172  * PARAMETERS:  Filename            - AML input filename
173  *              OutToFile           - TRUE if output should go to a file
174  *              Prefix              - Path prefix for output
175  *              OutFilename         - where the filename is returned
176  *
177  * RETURN:      Status
178  *
179  * DESCRIPTION: Disassembler entry point. Disassemble an entire ACPI table.
180  *
181  *****************************************************************************/
182 
183 ACPI_STATUS
184 AdAmlDisassemble (
185     BOOLEAN                 OutToFile,
186     char                    *Filename,
187     char                    *Prefix,
188     char                    **OutFilename)
189 {
190     ACPI_STATUS             Status;
191     char                    *DisasmFilename = NULL;
192     FILE                    *File = NULL;
193     ACPI_TABLE_HEADER       *Table = NULL;
194     ACPI_NEW_TABLE_DESC     *ListHead = NULL;
195 
196 
197     /*
198      * Input: AML code from either a file or via GetTables (memory or
199      * registry)
200      */
201     if (Filename)
202     {
203         /* Get the list of all AML tables in the file */
204 
205         Status = AcGetAllTablesFromFile (Filename,
206             ACPI_GET_ALL_TABLES, &ListHead);
207         if (ACPI_FAILURE (Status))
208         {
209             AcpiOsPrintf ("Could not get ACPI tables from %s, %s\n",
210                 Filename, AcpiFormatException (Status));
211             return (Status);
212         }
213 
214         /* Process any user-specified files for external objects */
215 
216         Status = AdDoExternalFileList (Filename);
217         if (ACPI_FAILURE (Status))
218         {
219             return (Status);
220         }
221     }
222     else
223     {
224         Status = AdGetLocalTables ();
225         if (ACPI_FAILURE (Status))
226         {
227             AcpiOsPrintf ("Could not get ACPI tables, %s\n",
228                 AcpiFormatException (Status));
229             return (Status);
230         }
231 
232         if (!AcpiGbl_DmOpt_Disasm)
233         {
234             return (AE_OK);
235         }
236 
237         /* Obtained the local tables, just disassemble the DSDT */
238 
239         Status = AcpiGetTable (ACPI_SIG_DSDT, 0, &Table);
240         if (ACPI_FAILURE (Status))
241         {
242             AcpiOsPrintf ("Could not get DSDT, %s\n",
243                 AcpiFormatException (Status));
244             return (Status);
245         }
246 
247         AcpiOsPrintf ("\nDisassembly of DSDT\n");
248         Prefix = AdGenerateFilename ("dsdt", Table->OemTableId);
249     }
250 
251     /*
252      * Output: ASL code. Redirect to a file if requested
253      */
254     if (OutToFile)
255     {
256         /* Create/Open a disassembly output file */
257 
258         DisasmFilename = FlGenerateFilename (Prefix, FILE_SUFFIX_DISASSEMBLY);
259         if (!DisasmFilename)
260         {
261             fprintf (stderr, "Could not generate output filename\n");
262             Status = AE_ERROR;
263             goto Cleanup;
264         }
265 
266         File = fopen (DisasmFilename, "w+");
267         if (!File)
268         {
269             fprintf (stderr, "Could not open output file %s\n",
270                 DisasmFilename);
271             Status = AE_ERROR;
272             goto Cleanup;
273         }
274 
275         AcpiOsRedirectOutput (File);
276     }
277 
278     *OutFilename = DisasmFilename;
279 
280     /* Disassemble all AML tables within the file */
281 
282     while (ListHead)
283     {
284         Status = AdDisassembleOneTable (ListHead->Table,
285             File, Filename, DisasmFilename);
286         if (ACPI_FAILURE (Status))
287         {
288             break;
289         }
290 
291         ListHead = ListHead->Next;
292     }
293 
294 Cleanup:
295 
296     if (Table &&
297         !AcpiGbl_ForceAmlDisassembly &&
298         !AcpiUtIsAmlTable (Table))
299     {
300         ACPI_FREE (Table);
301     }
302 
303     AcDeleteTableList (ListHead);
304 
305     if (File)
306     {
307         fclose (File);
308         AcpiOsRedirectOutput (stdout);
309     }
310 
311     AcpiPsDeleteParseTree (AcpiGbl_ParseOpRoot);
312     AcpiGbl_ParseOpRoot = NULL;
313     return (Status);
314 }
315 
316 
317 /******************************************************************************
318  *
319  * FUNCTION:    AdDisassembleOneTable
320  *
321  * PARAMETERS:  Table               - Raw AML table
322  *              File                - Pointer for the input file
323  *              Filename            - AML input filename
324  *              DisasmFilename      - Output filename
325  *
326  * RETURN:      Status
327  *
328  * DESCRIPTION: Disassemble a single ACPI table. AML or data table.
329  *
330  *****************************************************************************/
331 
332 static ACPI_STATUS
333 AdDisassembleOneTable (
334     ACPI_TABLE_HEADER       *Table,
335     FILE                    *File,
336     char                    *Filename,
337     char                    *DisasmFilename)
338 {
339     ACPI_STATUS             Status;
340     ACPI_OWNER_ID           OwnerId;
341 
342 
343 #ifdef ACPI_ASL_COMPILER
344 
345     /*
346      * For ASL-/ASL+ converter: replace the temporary "XXXX"
347      * table signature with the original. This "XXXX" makes
348      * it harder for the AML interpreter to run the badaml
349      * (.xxx) file produced from the converter in case if
350      * it fails to get deleted.
351      */
352     if (AcpiGbl_CaptureComments)
353     {
354         strncpy (Table->Signature, AcpiGbl_TableSig, ACPI_NAME_SIZE);
355     }
356 #endif
357 
358     /* ForceAmlDisassembly means to assume the table contains valid AML */
359 
360     if (!AcpiGbl_ForceAmlDisassembly && !AcpiUtIsAmlTable (Table))
361     {
362         AdDisassemblerHeader (Filename, ACPI_IS_DATA_TABLE);
363 
364         /* This is a "Data Table" (non-AML table) */
365 
366         AcpiOsPrintf (" * ACPI Data Table [%4.4s]\n *\n",
367             Table->Signature);
368         AcpiOsPrintf (" * Format: [HexOffset DecimalOffset ByteLength]  "
369             "FieldName : FieldValue\n */\n\n");
370 
371         AcpiDmDumpDataTable (Table);
372         fprintf (stderr, "Acpi Data Table [%4.4s] decoded\n",
373             Table->Signature);
374 
375         if (File)
376         {
377             fprintf (stderr, "Formatted output:  %s - %u bytes\n",
378                 DisasmFilename, CmGetFileSize (File));
379         }
380 
381         return (AE_OK);
382     }
383 
384     /*
385      * This is an AML table (DSDT or SSDT).
386      * Always parse the tables, only option is what to display
387      */
388     Status = AdParseTable (Table, &OwnerId, TRUE, FALSE);
389     if (ACPI_FAILURE (Status))
390     {
391         AcpiOsPrintf ("Could not parse ACPI tables, %s\n",
392             AcpiFormatException (Status));
393         return (Status);
394     }
395 
396     /* Debug output, namespace and parse tree */
397 
398     if (AslCompilerdebug && File)
399     {
400         AcpiOsPrintf ("/**** Before second load\n");
401 
402         NsSetupNamespaceListing (File);
403         NsDisplayNamespace ();
404 
405         AcpiOsPrintf ("*****/\n");
406     }
407 
408     /* Load namespace from names created within control methods */
409 
410     AcpiDmFinishNamespaceLoad (AcpiGbl_ParseOpRoot,
411         AcpiGbl_RootNode, OwnerId);
412 
413     /*
414      * Cross reference the namespace here, in order to
415      * generate External() statements
416      */
417     AcpiDmCrossReferenceNamespace (AcpiGbl_ParseOpRoot,
418         AcpiGbl_RootNode, OwnerId);
419 
420     if (AslCompilerdebug)
421     {
422         AcpiDmDumpTree (AcpiGbl_ParseOpRoot);
423     }
424 
425     /* Find possible calls to external control methods */
426 
427     AcpiDmFindOrphanMethods (AcpiGbl_ParseOpRoot);
428 
429     /*
430      * If we found any external control methods, we must reparse
431      * the entire tree with the new information (namely, the
432      * number of arguments per method)
433      */
434     if (AcpiDmGetUnresolvedExternalMethodCount ())
435     {
436         Status = AdReparseOneTable (Table, File, OwnerId);
437         if (ACPI_FAILURE (Status))
438         {
439             return (Status);
440         }
441     }
442 
443     /*
444      * Now that the namespace is finalized, we can perform namespace
445      * transforms.
446      *
447      * 1) Convert fixed-offset references to resource descriptors
448      *    to symbolic references (Note: modifies namespace)
449      */
450     AcpiDmConvertParseObjects (AcpiGbl_ParseOpRoot, AcpiGbl_RootNode);
451 
452     /* Optional displays */
453 
454     if (AcpiGbl_DmOpt_Disasm)
455     {
456         /* This is the real disassembly */
457 
458         AdDisplayTables (Filename, Table);
459 
460         /* Dump hex table if requested (-vt) */
461 
462         AcpiDmDumpDataTable (Table);
463 
464         fprintf (stderr, "Disassembly completed\n");
465         if (File)
466         {
467             fprintf (stderr, "ASL Output:    %s - %u bytes\n",
468                 DisasmFilename, CmGetFileSize (File));
469         }
470 
471         if (Gbl_MapfileFlag)
472         {
473             fprintf (stderr, "%14s %s - %u bytes\n",
474                 Gbl_Files[ASL_FILE_MAP_OUTPUT].ShortDescription,
475                 Gbl_Files[ASL_FILE_MAP_OUTPUT].Filename,
476                 FlGetFileSize (ASL_FILE_MAP_OUTPUT));
477         }
478     }
479 
480     return (AE_OK);
481 }
482 
483 
484 /******************************************************************************
485  *
486  * FUNCTION:    AdReparseOneTable
487  *
488  * PARAMETERS:  Table               - Raw AML table
489  *              File                - Pointer for the input file
490  *              OwnerId             - ID for this table
491  *
492  * RETURN:      Status
493  *
494  * DESCRIPTION: Reparse a table that has already been loaded. Used to
495  *              integrate information about external control methods.
496  *              These methods may have been previously parsed incorrectly.
497  *
498  *****************************************************************************/
499 
500 static ACPI_STATUS
501 AdReparseOneTable (
502     ACPI_TABLE_HEADER       *Table,
503     FILE                    *File,
504     ACPI_OWNER_ID           OwnerId)
505 {
506     ACPI_STATUS             Status;
507     ACPI_COMMENT_ADDR_NODE  *AddrListHead;
508 
509 
510     fprintf (stderr,
511         "\nFound %u external control methods, "
512         "reparsing with new information\n",
513         AcpiDmGetUnresolvedExternalMethodCount ());
514 
515     /* Reparse, rebuild namespace */
516 
517     AcpiPsDeleteParseTree (AcpiGbl_ParseOpRoot);
518     AcpiGbl_ParseOpRoot = NULL;
519     AcpiNsDeleteNamespaceSubtree (AcpiGbl_RootNode);
520 
521     AcpiGbl_RootNode                    = NULL;
522     AcpiGbl_RootNodeStruct.Name.Integer = ACPI_ROOT_NAME;
523     AcpiGbl_RootNodeStruct.DescriptorType = ACPI_DESC_TYPE_NAMED;
524     AcpiGbl_RootNodeStruct.Type         = ACPI_TYPE_DEVICE;
525     AcpiGbl_RootNodeStruct.Parent       = NULL;
526     AcpiGbl_RootNodeStruct.Child        = NULL;
527     AcpiGbl_RootNodeStruct.Peer         = NULL;
528     AcpiGbl_RootNodeStruct.Object       = NULL;
529     AcpiGbl_RootNodeStruct.Flags        = 0;
530 
531     Status = AcpiNsRootInitialize ();
532     if (ACPI_FAILURE (Status))
533     {
534         return (Status);
535     }
536 
537     /* New namespace, add the external definitions first */
538 
539     AcpiDmAddExternalListToNamespace ();
540 
541     /* For -ca option: clear the list of comment addresses. */
542 
543     while (AcpiGbl_CommentAddrListHead)
544     {
545         AddrListHead= AcpiGbl_CommentAddrListHead;
546         AcpiGbl_CommentAddrListHead = AcpiGbl_CommentAddrListHead->Next;
547         AcpiOsFree(AddrListHead);
548     }
549 
550     /* Parse the table again. No need to reload it, however */
551 
552     Status = AdParseTable (Table, NULL, FALSE, FALSE);
553     if (ACPI_FAILURE (Status))
554     {
555         AcpiOsPrintf ("Could not parse ACPI tables, %s\n",
556             AcpiFormatException (Status));
557         return (Status);
558     }
559 
560     /* Cross reference the namespace again */
561 
562     AcpiDmFinishNamespaceLoad (AcpiGbl_ParseOpRoot,
563         AcpiGbl_RootNode, OwnerId);
564 
565     AcpiDmCrossReferenceNamespace (AcpiGbl_ParseOpRoot,
566         AcpiGbl_RootNode, OwnerId);
567 
568     /* Debug output - namespace and parse tree */
569 
570     if (AslCompilerdebug)
571     {
572         AcpiOsPrintf ("/**** After second load and resource conversion\n");
573         if (File)
574         {
575             NsSetupNamespaceListing (File);
576             NsDisplayNamespace ();
577         }
578 
579         AcpiOsPrintf ("*****/\n");
580         AcpiDmDumpTree (AcpiGbl_ParseOpRoot);
581     }
582 
583     return (AE_OK);
584 }
585 
586 
587 /******************************************************************************
588  *
589  * FUNCTION:    AdDoExternalFileList
590  *
591  * PARAMETERS:  Filename            - Input file for the table
592  *
593  * RETURN:      Status
594  *
595  * DESCRIPTION: Process all tables found in the -e external files list
596  *
597  *****************************************************************************/
598 
599 static ACPI_STATUS
600 AdDoExternalFileList (
601     char                    *Filename)
602 {
603     ACPI_EXTERNAL_FILE      *ExternalFileList;
604     char                    *ExternalFilename;
605     ACPI_NEW_TABLE_DESC     *ExternalListHead = NULL;
606     ACPI_STATUS             Status;
607     ACPI_STATUS             GlobalStatus = AE_OK;
608     ACPI_OWNER_ID           OwnerId;
609 
610 
611     /*
612      * External filenames are specified on the command line like this:
613      * Example: iasl -e file1,file2,file3 -d xxx.aml
614      */
615     ExternalFileList = AcpiGbl_ExternalFileList;
616 
617     /* Process each external file */
618 
619     while (ExternalFileList)
620     {
621         ExternalFilename = ExternalFileList->Path;
622         if (!strcmp (ExternalFilename, Filename))
623         {
624             /* Next external file */
625 
626             ExternalFileList = ExternalFileList->Next;
627             continue;
628         }
629 
630         AcpiOsPrintf ("External object resolution file %16s\n",
631             ExternalFilename);
632 
633         Status = AcGetAllTablesFromFile (
634             ExternalFilename, ACPI_GET_ONLY_AML_TABLES, &ExternalListHead);
635         if (ACPI_FAILURE (Status))
636         {
637             if (Status == AE_TYPE)
638             {
639                 ExternalFileList = ExternalFileList->Next;
640                 GlobalStatus = AE_TYPE;
641                 Status = AE_OK;
642                 continue;
643             }
644 
645             AcDeleteTableList (ExternalListHead);
646             return (Status);
647         }
648 
649         /* Load external tables for symbol resolution */
650 
651         while (ExternalListHead)
652         {
653             Status = AdParseTable (
654                 ExternalListHead->Table, &OwnerId, TRUE, TRUE);
655             if (ACPI_FAILURE (Status))
656             {
657                 AcpiOsPrintf ("Could not parse external ACPI tables, %s\n",
658                     AcpiFormatException (Status));
659                 AcDeleteTableList (ExternalListHead);
660                 return (Status);
661             }
662 
663             /*
664              * Load namespace from names created within control methods
665              * Set owner id of nodes in external table
666              */
667             AcpiDmFinishNamespaceLoad (AcpiGbl_ParseOpRoot,
668                 AcpiGbl_RootNode, OwnerId);
669             AcpiPsDeleteParseTree (AcpiGbl_ParseOpRoot);
670 
671             ExternalListHead = ExternalListHead->Next;
672         }
673 
674         /* Next external file */
675 
676         ExternalFileList = ExternalFileList->Next;
677     }
678 
679     AcDeleteTableList (ExternalListHead);
680 
681     if (ACPI_FAILURE (GlobalStatus))
682     {
683         return (GlobalStatus);
684     }
685 
686     /* Clear external list generated by Scope in external tables */
687 
688     if (AcpiGbl_ExternalFileList)
689     {
690         AcpiDmClearExternalList ();
691     }
692 
693     /* Load any externals defined in the optional external ref file */
694 
695     AcpiDmGetExternalsFromFile ();
696     return (AE_OK);
697 }
698