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