1 /******************************************************************************
   2  *
   3  * Module Name: asllistsup - Listing file support utilities
   4  *
   5  *****************************************************************************/
   6 
   7 /*
   8  * Copyright (C) 2000 - 2014, 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 
  47 
  48 #define _COMPONENT          ACPI_COMPILER
  49         ACPI_MODULE_NAME    ("aslistsup")
  50 
  51 
  52 /*******************************************************************************
  53  *
  54  * FUNCTION:    LsDumpAscii
  55  *
  56  * PARAMETERS:  FileId          - ID of current listing file
  57  *              Count           - Number of bytes to convert
  58  *              Buffer          - Buffer of bytes to convert
  59  *
  60  * RETURN:      None
  61  *
  62  * DESCRIPTION: Convert hex bytes to ascii
  63  *
  64  ******************************************************************************/
  65 
  66 void
  67 LsDumpAscii (
  68     UINT32                  FileId,
  69     UINT32                  Count,
  70     UINT8                   *Buffer)
  71 {
  72     UINT8                   BufChar;
  73     UINT32                  i;
  74 
  75 
  76     FlPrintFile (FileId, "    \"");
  77     for (i = 0; i < Count; i++)
  78     {
  79         BufChar = Buffer[i];
  80         if (isprint (BufChar))
  81         {
  82             FlPrintFile (FileId, "%c", BufChar);
  83         }
  84         else
  85         {
  86             /* Not a printable character, just put out a dot */
  87 
  88             FlPrintFile (FileId, ".");
  89         }
  90     }
  91     FlPrintFile (FileId, "\"");
  92 }
  93 
  94 
  95 /*******************************************************************************
  96  *
  97  * FUNCTION:    LsDumpAsciiInComment
  98  *
  99  * PARAMETERS:  FileId          - ID of current listing file
 100  *              Count           - Number of bytes to convert
 101  *              Buffer          - Buffer of bytes to convert
 102  *
 103  * RETURN:      None
 104  *
 105  * DESCRIPTION: Convert hex bytes to ascii
 106  *
 107  ******************************************************************************/
 108 
 109 void
 110 LsDumpAsciiInComment (
 111     UINT32                  FileId,
 112     UINT32                  Count,
 113     UINT8                   *Buffer)
 114 {
 115     UINT8                   BufChar = 0;
 116     UINT8                   LastChar;
 117     UINT32                  i;
 118 
 119 
 120     FlPrintFile (FileId, "    \"");
 121     for (i = 0; i < Count; i++)
 122     {
 123         LastChar = BufChar;
 124         BufChar = Buffer[i];
 125 
 126         if (isprint (BufChar))
 127         {
 128             /* Handle embedded C comment sequences */
 129 
 130             if (((LastChar == '*') && (BufChar == '/')) ||
 131                 ((LastChar == '/') && (BufChar == '*')))
 132             {
 133                 /* Insert a space to break the sequence */
 134 
 135                 FlPrintFile (FileId, ".", BufChar);
 136             }
 137 
 138             FlPrintFile (FileId, "%c", BufChar);
 139         }
 140         else
 141         {
 142             /* Not a printable character, just put out a dot */
 143 
 144             FlPrintFile (FileId, ".");
 145         }
 146     }
 147 
 148     FlPrintFile (FileId, "\"");
 149 }
 150 
 151 
 152 /*******************************************************************************
 153  *
 154  * FUNCTION:    LsCheckException
 155  *
 156  * PARAMETERS:  LineNumber          - Current logical (cumulative) line #
 157  *              FileId              - ID of output listing file
 158  *
 159  * RETURN:      None
 160  *
 161  * DESCRIPTION: Check if there is an exception for this line, and if there is,
 162  *              put it in the listing immediately. Handles multiple errors
 163  *              per line. Gbl_NextError points to the next error in the
 164  *              sorted (by line #) list of compile errors/warnings.
 165  *
 166  ******************************************************************************/
 167 
 168 void
 169 LsCheckException (
 170     UINT32                  LineNumber,
 171     UINT32                  FileId)
 172 {
 173 
 174     if ((!Gbl_NextError) ||
 175         (LineNumber < Gbl_NextError->LogicalLineNumber ))
 176     {
 177         return;
 178     }
 179 
 180     /* Handle multiple errors per line */
 181 
 182     if (FileId == ASL_FILE_LISTING_OUTPUT)
 183     {
 184         while (Gbl_NextError &&
 185               (LineNumber >= Gbl_NextError->LogicalLineNumber))
 186         {
 187             AePrintException (FileId, Gbl_NextError, "\n[****iasl****]\n");
 188 
 189             Gbl_NextError = Gbl_NextError->Next;
 190         }
 191 
 192         FlPrintFile (FileId, "\n");
 193     }
 194 }
 195 
 196 
 197 /*******************************************************************************
 198  *
 199  * FUNCTION:    LsWriteListingHexBytes
 200  *
 201  * PARAMETERS:  Buffer          - AML code buffer
 202  *              Length          - Number of AML bytes to write
 203  *              FileId          - ID of current listing file.
 204  *
 205  * RETURN:      None
 206  *
 207  * DESCRIPTION: Write the contents of the AML buffer to the listing file via
 208  *              the listing buffer. The listing buffer is flushed every 16
 209  *              AML bytes.
 210  *
 211  ******************************************************************************/
 212 
 213 void
 214 LsWriteListingHexBytes (
 215     UINT8                   *Buffer,
 216     UINT32                  Length,
 217     UINT32                  FileId)
 218 {
 219     UINT32                  i;
 220 
 221 
 222     /* Transfer all requested bytes */
 223 
 224     for (i = 0; i < Length; i++)
 225     {
 226         /* Print line header when buffer is empty */
 227 
 228         if (Gbl_CurrentHexColumn == 0)
 229         {
 230             if (Gbl_HasIncludeFiles)
 231             {
 232                 FlPrintFile (FileId, "%*s", 10, " ");
 233             }
 234 
 235             switch (FileId)
 236             {
 237             case ASL_FILE_LISTING_OUTPUT:
 238 
 239                 FlPrintFile (FileId, "%8.8X%s", Gbl_CurrentAmlOffset,
 240                     ASL_LISTING_LINE_PREFIX);
 241                 break;
 242 
 243             case ASL_FILE_ASM_SOURCE_OUTPUT:
 244 
 245                 FlPrintFile (FileId, "    db ");
 246                 break;
 247 
 248             case ASL_FILE_C_SOURCE_OUTPUT:
 249 
 250                 FlPrintFile (FileId, "        ");
 251                 break;
 252 
 253             default:
 254 
 255                 /* No other types supported */
 256 
 257                 return;
 258             }
 259         }
 260 
 261         /* Transfer AML byte and update counts */
 262 
 263         Gbl_AmlBuffer[Gbl_CurrentHexColumn] = Buffer[i];
 264 
 265         Gbl_CurrentHexColumn++;
 266         Gbl_CurrentAmlOffset++;
 267 
 268         /* Flush buffer when it is full */
 269 
 270         if (Gbl_CurrentHexColumn >= HEX_LISTING_LINE_SIZE)
 271         {
 272             LsFlushListingBuffer (FileId);
 273         }
 274     }
 275 }
 276 
 277 
 278 /*******************************************************************************
 279  *
 280  * FUNCTION:    LsWriteSourceLines
 281  *
 282  * PARAMETERS:  ToLineNumber            -
 283  *              ToLogicalLineNumber     - Write up to this source line number
 284  *              FileId                  - ID of current listing file
 285  *
 286  * RETURN:      None
 287  *
 288  * DESCRIPTION: Read then write source lines to the listing file until we have
 289  *              reached the specified logical (cumulative) line number. This
 290  *              automatically echos out comment blocks and other non-AML
 291  *              generating text until we get to the actual AML-generating line
 292  *              of ASL code specified by the logical line number.
 293  *
 294  ******************************************************************************/
 295 
 296 void
 297 LsWriteSourceLines (
 298     UINT32                  ToLineNumber,
 299     UINT32                  ToLogicalLineNumber,
 300     UINT32                  FileId)
 301 {
 302 
 303     /* Nothing to do for these file types */
 304 
 305     if ((FileId == ASL_FILE_ASM_INCLUDE_OUTPUT) ||
 306         (FileId == ASL_FILE_C_INCLUDE_OUTPUT))
 307     {
 308         return;
 309     }
 310 
 311     Gbl_CurrentLine = ToLogicalLineNumber;
 312 
 313     /* Flush any hex bytes remaining from the last opcode */
 314 
 315     LsFlushListingBuffer (FileId);
 316 
 317     /* Read lines and write them as long as we are not caught up */
 318 
 319     if (Gbl_SourceLine < Gbl_CurrentLine)
 320     {
 321         /*
 322          * If we just completed writing some AML hex bytes, output a linefeed
 323          * to add some whitespace for readability.
 324          */
 325         if (Gbl_HexBytesWereWritten)
 326         {
 327             FlPrintFile (FileId, "\n");
 328             Gbl_HexBytesWereWritten = FALSE;
 329         }
 330 
 331         if (FileId == ASL_FILE_C_SOURCE_OUTPUT)
 332         {
 333             FlPrintFile (FileId, "    /*\n");
 334         }
 335 
 336         /* Write one line at a time until we have reached the target line # */
 337 
 338         while ((Gbl_SourceLine < Gbl_CurrentLine) &&
 339                 LsWriteOneSourceLine (FileId))
 340         { ; }
 341 
 342         if (FileId == ASL_FILE_C_SOURCE_OUTPUT)
 343         {
 344             FlPrintFile (FileId, "     */");
 345         }
 346 
 347         FlPrintFile (FileId, "\n");
 348     }
 349 }
 350 
 351 
 352 /*******************************************************************************
 353  *
 354  * FUNCTION:    LsWriteOneSourceLine
 355  *
 356  * PARAMETERS:  FileId          - ID of current listing file
 357  *
 358  * RETURN:      FALSE on EOF (input source file), TRUE otherwise
 359  *
 360  * DESCRIPTION: Read one line from the input source file and echo it to the
 361  *              listing file, prefixed with the line number, and if the source
 362  *              file contains include files, prefixed with the current filename
 363  *
 364  ******************************************************************************/
 365 
 366 UINT32
 367 LsWriteOneSourceLine (
 368     UINT32                  FileId)
 369 {
 370     UINT8                   FileByte;
 371     UINT32                  Column = 0;
 372     UINT32                  Index = 16;
 373     BOOLEAN                 StartOfLine = FALSE;
 374     BOOLEAN                 ProcessLongLine = FALSE;
 375 
 376 
 377     Gbl_SourceLine++;
 378     Gbl_ListingNode->LineNumber++;
 379 
 380     /* Ignore lines that are completely blank (but count the line above) */
 381 
 382     if (FlReadFile (ASL_FILE_SOURCE_OUTPUT, &FileByte, 1) != AE_OK)
 383     {
 384         return (0);
 385     }
 386     if (FileByte == '\n')
 387     {
 388         return (1);
 389     }
 390 
 391     /*
 392      * This is a non-empty line, we will print the entire line with
 393      * the line number and possibly other prefixes and transforms.
 394      */
 395 
 396     /* Line prefixes for special files, C and ASM output */
 397 
 398     if (FileId == ASL_FILE_C_SOURCE_OUTPUT)
 399     {
 400         FlPrintFile (FileId, "     *");
 401     }
 402     if (FileId == ASL_FILE_ASM_SOURCE_OUTPUT)
 403     {
 404         FlPrintFile (FileId, "; ");
 405     }
 406 
 407     if (Gbl_HasIncludeFiles)
 408     {
 409         /*
 410          * This file contains "include" statements, print the current
 411          * filename and line number within the current file
 412          */
 413         FlPrintFile (FileId, "%12s %5d%s",
 414             Gbl_ListingNode->Filename, Gbl_ListingNode->LineNumber,
 415             ASL_LISTING_LINE_PREFIX);
 416     }
 417     else
 418     {
 419         /* No include files, just print the line number */
 420 
 421         FlPrintFile (FileId, "%8u%s", Gbl_SourceLine,
 422             ASL_LISTING_LINE_PREFIX);
 423     }
 424 
 425     /* Read the rest of this line (up to a newline or EOF) */
 426 
 427     do
 428     {
 429         if (FileId == ASL_FILE_C_SOURCE_OUTPUT)
 430         {
 431             if (FileByte == '/')
 432             {
 433                 FileByte = '*';
 434             }
 435         }
 436 
 437         /* Split long input lines for readability in the listing */
 438 
 439         Column++;
 440         if (Column >= 128)
 441         {
 442             if (!ProcessLongLine)
 443             {
 444                 if ((FileByte != '}') &&
 445                     (FileByte != '{'))
 446                 {
 447                     goto WriteByte;
 448                 }
 449 
 450                 ProcessLongLine = TRUE;
 451             }
 452 
 453             if (FileByte == '{')
 454             {
 455                 FlPrintFile (FileId, "\n%*s{\n", Index, " ");
 456                 StartOfLine = TRUE;
 457                 Index += 4;
 458                 continue;
 459             }
 460 
 461             else if (FileByte == '}')
 462             {
 463                 if (!StartOfLine)
 464                 {
 465                     FlPrintFile (FileId, "\n");
 466                 }
 467 
 468                 StartOfLine = TRUE;
 469                 Index -= 4;
 470                 FlPrintFile (FileId, "%*s}\n", Index, " ");
 471                 continue;
 472             }
 473 
 474             /* Ignore spaces/tabs at the start of line */
 475 
 476             else if ((FileByte == ' ') && StartOfLine)
 477             {
 478                 continue;
 479             }
 480 
 481             else if (StartOfLine)
 482             {
 483                 StartOfLine = FALSE;
 484                 FlPrintFile (FileId, "%*s", Index, " ");
 485             }
 486 
 487 WriteByte:
 488             FlWriteFile (FileId, &FileByte, 1);
 489             if (FileByte == '\n')
 490             {
 491                 /*
 492                  * This line has been completed.
 493                  * Check if an error occurred on this source line during the compile.
 494                  * If so, we print the error message after the source line.
 495                  */
 496                 LsCheckException (Gbl_SourceLine, FileId);
 497                 return (1);
 498             }
 499         }
 500         else
 501         {
 502             FlWriteFile (FileId, &FileByte, 1);
 503             if (FileByte == '\n')
 504             {
 505                 /*
 506                  * This line has been completed.
 507                  * Check if an error occurred on this source line during the compile.
 508                  * If so, we print the error message after the source line.
 509                  */
 510                 LsCheckException (Gbl_SourceLine, FileId);
 511                 return (1);
 512             }
 513         }
 514 
 515     } while (FlReadFile (ASL_FILE_SOURCE_OUTPUT, &FileByte, 1) == AE_OK);
 516 
 517     /* EOF on the input file was reached */
 518 
 519     return (0);
 520 }
 521 
 522 
 523 /*******************************************************************************
 524  *
 525  * FUNCTION:    LsFlushListingBuffer
 526  *
 527  * PARAMETERS:  FileId          - ID of the listing file
 528  *
 529  * RETURN:      None
 530  *
 531  * DESCRIPTION: Flush out the current contents of the 16-byte hex AML code
 532  *              buffer. Usually called at the termination of a single line
 533  *              of source code or when the buffer is full.
 534  *
 535  ******************************************************************************/
 536 
 537 void
 538 LsFlushListingBuffer (
 539     UINT32                  FileId)
 540 {
 541     UINT32                  i;
 542 
 543 
 544     if (Gbl_CurrentHexColumn == 0)
 545     {
 546         return;
 547     }
 548 
 549     /* Write the hex bytes */
 550 
 551     switch (FileId)
 552     {
 553     case ASL_FILE_LISTING_OUTPUT:
 554 
 555         for (i = 0; i < Gbl_CurrentHexColumn; i++)
 556         {
 557             FlPrintFile (FileId, "%2.2X ", Gbl_AmlBuffer[i]);
 558         }
 559 
 560         for (i = 0; i < ((HEX_LISTING_LINE_SIZE - Gbl_CurrentHexColumn) * 3); i++)
 561         {
 562             FlWriteFile (FileId, ".", 1);
 563         }
 564 
 565         /* Write the ASCII character associated with each of the bytes */
 566 
 567         LsDumpAscii (FileId, Gbl_CurrentHexColumn, Gbl_AmlBuffer);
 568         break;
 569 
 570 
 571     case ASL_FILE_ASM_SOURCE_OUTPUT:
 572 
 573         for (i = 0; i < Gbl_CurrentHexColumn; i++)
 574         {
 575             if (i > 0)
 576             {
 577                 FlPrintFile (FileId, ",");
 578             }
 579             FlPrintFile (FileId, "0%2.2Xh", Gbl_AmlBuffer[i]);
 580         }
 581 
 582         for (i = 0; i < ((HEX_LISTING_LINE_SIZE - Gbl_CurrentHexColumn) * 5); i++)
 583         {
 584             FlWriteFile (FileId, " ", 1);
 585         }
 586 
 587         FlPrintFile (FileId, "  ;%8.8X",
 588             Gbl_CurrentAmlOffset - HEX_LISTING_LINE_SIZE);
 589 
 590         /* Write the ASCII character associated with each of the bytes */
 591 
 592         LsDumpAscii (FileId, Gbl_CurrentHexColumn, Gbl_AmlBuffer);
 593         break;
 594 
 595 
 596     case ASL_FILE_C_SOURCE_OUTPUT:
 597 
 598         for (i = 0; i < Gbl_CurrentHexColumn; i++)
 599         {
 600             FlPrintFile (FileId, "0x%2.2X,", Gbl_AmlBuffer[i]);
 601         }
 602 
 603         /* Pad hex output with spaces if line is shorter than max line size */
 604 
 605         for (i = 0; i < ((HEX_LISTING_LINE_SIZE - Gbl_CurrentHexColumn) * 5); i++)
 606         {
 607             FlWriteFile (FileId, " ", 1);
 608         }
 609 
 610         /* AML offset for the start of the line */
 611 
 612         FlPrintFile (FileId, "    /* %8.8X",
 613             Gbl_CurrentAmlOffset - Gbl_CurrentHexColumn);
 614 
 615         /* Write the ASCII character associated with each of the bytes */
 616 
 617         LsDumpAsciiInComment (FileId, Gbl_CurrentHexColumn, Gbl_AmlBuffer);
 618         FlPrintFile (FileId, " */");
 619         break;
 620 
 621     default:
 622 
 623         /* No other types supported */
 624 
 625         return;
 626     }
 627 
 628     FlPrintFile (FileId, "\n");
 629 
 630     Gbl_CurrentHexColumn = 0;
 631     Gbl_HexBytesWereWritten = TRUE;
 632 }
 633 
 634 
 635 /*******************************************************************************
 636  *
 637  * FUNCTION:    LsPushNode
 638  *
 639  * PARAMETERS:  Filename        - Pointer to the include filename
 640  *
 641  * RETURN:      None
 642  *
 643  * DESCRIPTION: Push a listing node on the listing/include file stack. This
 644  *              stack enables tracking of include files (infinitely nested)
 645  *              and resumption of the listing of the parent file when the
 646  *              include file is finished.
 647  *
 648  ******************************************************************************/
 649 
 650 void
 651 LsPushNode (
 652     char                    *Filename)
 653 {
 654     ASL_LISTING_NODE        *Lnode;
 655 
 656 
 657     /* Create a new node */
 658 
 659     Lnode = UtLocalCalloc (sizeof (ASL_LISTING_NODE));
 660 
 661     /* Initialize */
 662 
 663     Lnode->Filename = Filename;
 664     Lnode->LineNumber = 0;
 665 
 666     /* Link (push) */
 667 
 668     Lnode->Next = Gbl_ListingNode;
 669     Gbl_ListingNode = Lnode;
 670 }
 671 
 672 
 673 /*******************************************************************************
 674  *
 675  * FUNCTION:    LsPopNode
 676  *
 677  * PARAMETERS:  None
 678  *
 679  * RETURN:      List head after current head is popped off
 680  *
 681  * DESCRIPTION: Pop the current head of the list, free it, and return the
 682  *              next node on the stack (the new current node).
 683  *
 684  ******************************************************************************/
 685 
 686 ASL_LISTING_NODE *
 687 LsPopNode (
 688     void)
 689 {
 690     ASL_LISTING_NODE        *Lnode;
 691 
 692 
 693     /* Just grab the node at the head of the list */
 694 
 695     Lnode = Gbl_ListingNode;
 696     if ((!Lnode) ||
 697         (!Lnode->Next))
 698     {
 699         AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, NULL,
 700             "Could not pop empty listing stack");
 701         return (Gbl_ListingNode);
 702     }
 703 
 704     Gbl_ListingNode = Lnode->Next;
 705     ACPI_FREE (Lnode);
 706 
 707     /* New "Current" node is the new head */
 708 
 709     return (Gbl_ListingNode);
 710 }