1 /****************************************************************************** 2 * 3 * Module Name: prmacros - Preprocessor #define macro support 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2023, 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 46 #define _COMPONENT ASL_PREPROCESSOR 47 ACPI_MODULE_NAME ("prmacros") 48 49 50 /******************************************************************************* 51 * 52 * FUNCTION: PrDumpPredefinedNames 53 * 54 * PARAMETERS: None 55 * 56 * RETURN: None 57 * 58 * DESCRIPTION: Dump the list of #defines. Used as the preprocessor starts, to 59 * display the names that were defined on the command line. 60 * Debug information only. 61 * 62 ******************************************************************************/ 63 64 void 65 PrDumpPredefinedNames ( 66 void) 67 { 68 PR_DEFINE_INFO *DefineInfo; 69 70 71 DefineInfo = AslGbl_DefineList; 72 while (DefineInfo) 73 { 74 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID 75 "Predefined #define: %s->%s\n", 76 0, DefineInfo->Identifier, DefineInfo->Replacement); 77 78 DefineInfo = DefineInfo->Next; 79 } 80 } 81 82 83 /******************************************************************************* 84 * 85 * FUNCTION: PrAddDefine 86 * 87 * PARAMETERS: Identifier - Name to be replaced 88 * Replacement - Replacement for Identifier 89 * Persist - Keep define across multiple compiles? 90 * 91 * RETURN: A new define_info struct. NULL on error. 92 * 93 * DESCRIPTION: Add a new #define to the global list 94 * 95 ******************************************************************************/ 96 97 PR_DEFINE_INFO * 98 PrAddDefine ( 99 char *Identifier, 100 char *Replacement, 101 BOOLEAN Persist) 102 { 103 char *IdentifierString; 104 char *ReplacementString; 105 PR_DEFINE_INFO *DefineInfo; 106 107 108 if (!Replacement) 109 { 110 Replacement = ""; 111 } 112 113 /* Check for already-defined first */ 114 115 DefineInfo = PrMatchDefine (Identifier); 116 if (DefineInfo) 117 { 118 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID 119 "#define: name already exists: %s\n", 120 AslGbl_CurrentLineNumber, Identifier); 121 122 /* 123 * Name already exists. This is only an error if the target name 124 * is different. 125 */ 126 if (strcmp (Replacement, DefineInfo->Replacement)) 127 { 128 PrError (ASL_ERROR, ASL_MSG_EXISTING_NAME, 129 THIS_TOKEN_OFFSET (Identifier)); 130 131 return (NULL); 132 } 133 134 return (DefineInfo); 135 } 136 137 /* Copy input strings */ 138 139 IdentifierString = UtLocalCalloc (strlen (Identifier) + 1); 140 strcpy (IdentifierString, Identifier); 141 142 ReplacementString = UtLocalCalloc (strlen (Replacement) + 1); 143 strcpy (ReplacementString, Replacement); 144 145 /* Init and link new define info struct */ 146 147 DefineInfo = UtLocalCalloc (sizeof (PR_DEFINE_INFO)); 148 DefineInfo->Replacement = ReplacementString; 149 DefineInfo->Identifier = IdentifierString; 150 DefineInfo->Persist = Persist; 151 152 if (AslGbl_DefineList) 153 { 154 AslGbl_DefineList->Previous = DefineInfo; 155 } 156 157 DefineInfo->Next = AslGbl_DefineList; 158 AslGbl_DefineList = DefineInfo; 159 return (DefineInfo); 160 } 161 162 163 /******************************************************************************* 164 * 165 * FUNCTION: PrRemoveDefine 166 * 167 * PARAMETERS: DefineName - Name of define to be removed 168 * 169 * RETURN: None 170 * 171 * DESCRIPTION: Implements #undef. Remove a #define if found in the global 172 * list. No error if the target of the #undef does not exist, 173 * as per the C #undef definition. 174 * 175 ******************************************************************************/ 176 177 void 178 PrRemoveDefine ( 179 char *DefineName) 180 { 181 PR_DEFINE_INFO *DefineInfo; 182 183 184 /* Match name and delete the node */ 185 186 DefineInfo = AslGbl_DefineList; 187 while (DefineInfo) 188 { 189 if (!strcmp (DefineName, DefineInfo->Identifier)) 190 { 191 /* Remove from linked list */ 192 193 if (DefineInfo->Previous) 194 { 195 (DefineInfo->Previous)->Next = DefineInfo->Next; 196 } 197 else 198 { 199 AslGbl_DefineList = DefineInfo->Next; 200 } 201 202 if (DefineInfo->Next) 203 { 204 (DefineInfo->Next)->Previous = DefineInfo->Previous; 205 } 206 207 free (DefineInfo); 208 return; 209 } 210 211 DefineInfo = DefineInfo->Next; 212 } 213 214 /* 215 * Name was not found. By definition of #undef, this is not 216 * an error, however. 217 */ 218 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID 219 "#undef: could not find %s\n", 220 AslGbl_CurrentLineNumber, DefineName); 221 } 222 223 224 /******************************************************************************* 225 * 226 * FUNCTION: PrMatchDefine 227 * 228 * PARAMETERS: MatchString - Name associated with the #define 229 * 230 * RETURN: Matched string if found. NULL otherwise. 231 * 232 * DESCRIPTION: Find a name in global #define list 233 * 234 ******************************************************************************/ 235 236 PR_DEFINE_INFO * 237 PrMatchDefine ( 238 char *MatchString) 239 { 240 PR_DEFINE_INFO *DefineInfo; 241 242 243 DefineInfo = AslGbl_DefineList; 244 while (DefineInfo) 245 { 246 if (!strcmp (MatchString, DefineInfo->Identifier)) 247 { 248 return (DefineInfo); 249 } 250 251 DefineInfo = DefineInfo->Next; 252 } 253 254 return (NULL); 255 } 256 257 258 /******************************************************************************* 259 * 260 * FUNCTION: PrAddMacro 261 * 262 * PARAMETERS: Name - Start of the macro definition 263 * Next - "Next" buffer from GetNextToken 264 * 265 * RETURN: None 266 * 267 * DESCRIPTION: Add a new macro to the list of #defines. Handles argument 268 * processing. 269 * 270 ******************************************************************************/ 271 272 void 273 PrAddMacro ( 274 char *Name, 275 char **Next) 276 { 277 char *Token = NULL; 278 ACPI_SIZE TokenOffset; 279 ACPI_SIZE MacroBodyOffset; 280 PR_DEFINE_INFO *DefineInfo; 281 PR_MACRO_ARG *Args; 282 char *Body; 283 char *BodyInSource; 284 UINT32 i; 285 UINT16 UseCount = 0; 286 UINT16 ArgCount = 0; 287 UINT32 Depth = 1; 288 /*UINT32 Depth = 1;*/ 289 UINT32 EndOfArgList; 290 char BufferChar; 291 292 /* Find the end of the arguments list */ 293 294 TokenOffset = Name - AslGbl_MainTokenBuffer + strlen (Name) + 1; 295 while (1) 296 { 297 BufferChar = AslGbl_CurrentLineBuffer[TokenOffset]; 298 if (BufferChar == '(') 299 { 300 Depth++; 301 } 302 else if (BufferChar == ')') 303 { 304 Depth--; 305 } 306 else if (BufferChar == 0) 307 { 308 PrError (ASL_ERROR, ASL_MSG_MACRO_SYNTAX, TokenOffset); 309 return; 310 } 311 312 if (Depth == 0) 313 { 314 /* Found arg list end */ 315 316 EndOfArgList = TokenOffset; 317 break; 318 } 319 320 TokenOffset++; 321 } 322 323 /* At this point, we know that we have a reasonable argument list */ 324 325 Args = UtLocalCalloc (sizeof (PR_MACRO_ARG) * PR_MAX_MACRO_ARGS); 326 327 /* Get the macro argument names */ 328 329 for (i = 0; i < PR_MAX_MACRO_ARGS; i++) 330 { 331 Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next); 332 333 if (!Token) 334 { 335 /* This is the case for a NULL macro body */ 336 337 BodyInSource = ""; 338 goto AddMacroToList; 339 } 340 341 /* Don't go beyond the argument list */ 342 343 TokenOffset = Token - AslGbl_MainTokenBuffer + strlen (Token); 344 if (TokenOffset > EndOfArgList) 345 { 346 break; 347 } 348 349 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID 350 "Macro param: %s\n", 351 AslGbl_CurrentLineNumber, Token); 352 353 Args[i].Name = UtLocalCalloc (strlen (Token) + 1); 354 strcpy (Args[i].Name, Token); 355 356 Args[i].UseCount = 0; 357 ArgCount++; 358 if (ArgCount >= PR_MAX_MACRO_ARGS) 359 { 360 PrError (ASL_ERROR, ASL_MSG_TOO_MANY_ARGUMENTS, TokenOffset); 361 goto ErrorExit; 362 } 363 } 364 365 /* Get the macro body. Token now points to start of body */ 366 367 MacroBodyOffset = Token - AslGbl_MainTokenBuffer; 368 369 /* Match each method arg in the macro body for later use */ 370 371 while (Token) 372 { 373 /* Search the macro arg list for matching arg */ 374 375 for (i = 0; ((i < PR_MAX_MACRO_ARGS) && Args[i].Name); i++) 376 { 377 /* 378 * Save argument offset within macro body. This is the mechanism 379 * used to expand the macro upon invocation. 380 * 381 * Handles multiple instances of the same argument 382 */ 383 if (!strcmp (Token, Args[i].Name)) 384 { 385 UseCount = Args[i].UseCount; 386 387 Args[i].Offset[UseCount] = 388 (Token - AslGbl_MainTokenBuffer) - MacroBodyOffset; 389 390 391 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID 392 "Macro Arg #%u: %s UseCount %u Offset %u\n", 393 AslGbl_CurrentLineNumber, i, Token, 394 UseCount+1, Args[i].Offset[UseCount]); 395 396 Args[i].UseCount++; 397 398 if (Args[i].UseCount >= PR_MAX_ARG_INSTANCES) 399 { 400 PrError (ASL_ERROR, ASL_MSG_TOO_MANY_ARGUMENTS, 401 THIS_TOKEN_OFFSET (Token)); 402 403 goto ErrorExit; 404 } 405 break; 406 } 407 } 408 409 Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next); 410 } 411 412 BodyInSource = &AslGbl_CurrentLineBuffer[MacroBodyOffset]; 413 414 415 AddMacroToList: 416 417 /* Check if name is already defined first */ 418 419 DefineInfo = PrMatchDefine (Name); 420 if (DefineInfo) 421 { 422 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID 423 "#define: macro name already exists: %s\n", 424 AslGbl_CurrentLineNumber, Name); 425 426 /* Error only if not exactly the same macro */ 427 428 if (strcmp (DefineInfo->Body, BodyInSource) || 429 (DefineInfo->ArgCount != ArgCount)) 430 { 431 PrError (ASL_ERROR, ASL_MSG_EXISTING_NAME, 432 THIS_TOKEN_OFFSET (Name)); 433 } 434 435 goto ErrorExit; 436 } 437 438 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID 439 "Macro body: %s\n", 440 AslGbl_CurrentLineNumber, BodyInSource); 441 442 /* Add macro to the #define list */ 443 444 DefineInfo = PrAddDefine (Name, BodyInSource, FALSE); 445 if (DefineInfo) 446 { 447 Body = UtLocalCalloc (strlen (BodyInSource) + 1); 448 strcpy (Body, BodyInSource); 449 450 DefineInfo->Body = Body; 451 DefineInfo->Args = Args; 452 DefineInfo->ArgCount = ArgCount; 453 } 454 455 return; 456 457 458 ErrorExit: 459 ACPI_FREE (Args); 460 return; 461 } 462 463 464 /******************************************************************************* 465 * 466 * FUNCTION: PrDoMacroInvocation 467 * 468 * PARAMETERS: TokenBuffer - Current line buffer 469 * MacroStart - Start of the macro invocation within 470 * the token buffer 471 * DefineInfo - Info for this macro 472 * Next - "Next" buffer from GetNextToken 473 * 474 * RETURN: None 475 * 476 * DESCRIPTION: Expand a macro invocation 477 * 478 ******************************************************************************/ 479 480 void 481 PrDoMacroInvocation ( 482 char *TokenBuffer, 483 char *MacroStart, 484 PR_DEFINE_INFO *DefineInfo, 485 char **Next) 486 { 487 PR_MACRO_ARG *Args; 488 char *Token = NULL; 489 UINT32 TokenOffset; 490 UINT32 Length; 491 UINT32 i; 492 UINT32 Diff1; 493 UINT32 Diff2; 494 495 /* Take a copy of the macro body for expansion */ 496 497 strcpy (AslGbl_MacroTokenBuffer, DefineInfo->Body); 498 499 /* Replace each argument within the prototype body */ 500 501 Args = DefineInfo->Args; 502 if (!Args->Name) 503 { 504 /* This macro has no arguments */ 505 506 Token = PrGetNextToken (NULL, PR_MACRO_ARGUMENTS, Next); 507 508 if (!Token) 509 { 510 goto BadInvocation; 511 } 512 513 TokenOffset = (MacroStart - TokenBuffer); 514 Length = Token - MacroStart + strlen (Token) + 1; 515 516 PrReplaceData ( 517 &AslGbl_CurrentLineBuffer[TokenOffset], Length, 518 AslGbl_MacroTokenBuffer, strlen (AslGbl_MacroTokenBuffer)); 519 return; 520 } 521 522 while (Args->Name) 523 { 524 /* Get the next argument from macro invocation */ 525 526 Token = PrGetNextToken (NULL, PR_MACRO_SEPARATORS, Next); 527 if (!Token) 528 { 529 goto BadInvocation; 530 } 531 532 /* 533 * Avoid optimizing using just 1 signed int due to specific 534 * non-portable implementations of signed ints 535 */ 536 Diff1 = strlen (Args->Name) > strlen (Token) ? strlen (Args->Name) - 537 strlen (Token) : 0; 538 539 Diff2 = strlen (Args->Name) < strlen (Token) ? strlen (Token) - 540 strlen (Args->Name) : 0; 541 542 /* Replace all instances of this argument */ 543 544 for (i = 0; i < Args->UseCount; i++) 545 { 546 /* 547 * To test the output of the preprocessed macro function that 548 * is passed to the compiler 549 */ 550 551 /* 552 * fprintf (stderr, "Current token = %s \t Current arg_name = %s \ 553 * \t strlen (Token) = %u \t strlen (Args->Name) = %u \t Offset = %u \ 554 * \t UseCount = %u \t", Token, Args->Name, strlen (Token), \ 555 * strlen (Args->Name), Args->Offset[i], Args->UseCount); 556 */ 557 558 AslGbl_MacroTokenReplaceBuffer = (char *) calloc ((strlen (AslGbl_MacroTokenBuffer)), sizeof (char)); 559 560 PrReplaceResizeSubstring (Args, Diff1, Diff2, i, Token); 561 562 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID 563 "ExpandArg: %s\n", 564 AslGbl_CurrentLineNumber, AslGbl_MacroTokenBuffer); 565 } 566 567 Args++; 568 } 569 570 if (!Token) 571 { 572 return; 573 } 574 575 /* Replace the entire macro invocation with the expanded macro */ 576 577 TokenOffset = (MacroStart - TokenBuffer); 578 Length = Token - MacroStart + strlen (Token) + 1; 579 580 PrReplaceData ( 581 &AslGbl_CurrentLineBuffer[TokenOffset], Length, 582 AslGbl_MacroTokenBuffer, strlen (AslGbl_MacroTokenBuffer)); 583 584 return; 585 586 BadInvocation: 587 PrError (ASL_ERROR, ASL_MSG_INVALID_INVOCATION, 588 THIS_TOKEN_OFFSET (MacroStart)); 589 590 DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID 591 "Bad macro invocation: %s\n", 592 AslGbl_CurrentLineNumber, AslGbl_MacroTokenBuffer); 593 return; 594 } 595