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