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