1 /******************************************************************************* 2 * 3 * Module Name: dbmethod - Debug commands for control methods 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 "acpi.h" 45 #include "accommon.h" 46 #include "acdispat.h" 47 #include "acnamesp.h" 48 #include "acdebug.h" 49 #include "acparser.h" 50 #include "acpredef.h" 51 52 53 #define _COMPONENT ACPI_CA_DEBUGGER 54 ACPI_MODULE_NAME ("dbmethod") 55 56 /* Local prototypes */ 57 58 static ACPI_STATUS 59 AcpiDbWalkForExecute ( 60 ACPI_HANDLE ObjHandle, 61 UINT32 NestingLevel, 62 void *Context, 63 void **ReturnValue); 64 65 static ACPI_STATUS 66 AcpiDbEvaluateObject ( 67 ACPI_NAMESPACE_NODE *Node); 68 69 70 /******************************************************************************* 71 * 72 * FUNCTION: AcpiDbSetMethodBreakpoint 73 * 74 * PARAMETERS: Location - AML offset of breakpoint 75 * WalkState - Current walk info 76 * Op - Current Op (from parse walk) 77 * 78 * RETURN: None 79 * 80 * DESCRIPTION: Set a breakpoint in a control method at the specified 81 * AML offset 82 * 83 ******************************************************************************/ 84 85 void 86 AcpiDbSetMethodBreakpoint ( 87 char *Location, 88 ACPI_WALK_STATE *WalkState, 89 ACPI_PARSE_OBJECT *Op) 90 { 91 UINT32 Address; 92 UINT32 AmlOffset; 93 94 95 if (!Op) 96 { 97 AcpiOsPrintf ("There is no method currently executing\n"); 98 return; 99 } 100 101 /* Get and verify the breakpoint address */ 102 103 Address = strtoul (Location, NULL, 16); 104 AmlOffset = (UINT32) ACPI_PTR_DIFF (Op->Common.Aml, 105 WalkState->ParserState.AmlStart); 106 if (Address <= AmlOffset) 107 { 108 AcpiOsPrintf ("Breakpoint %X is beyond current address %X\n", 109 Address, AmlOffset); 110 } 111 112 /* Save breakpoint in current walk */ 113 114 WalkState->UserBreakpoint = Address; 115 AcpiOsPrintf ("Breakpoint set at AML offset %X\n", Address); 116 } 117 118 119 /******************************************************************************* 120 * 121 * FUNCTION: AcpiDbSetMethodCallBreakpoint 122 * 123 * PARAMETERS: Op - Current Op (from parse walk) 124 * 125 * RETURN: None 126 * 127 * DESCRIPTION: Set a breakpoint in a control method at the specified 128 * AML offset 129 * 130 ******************************************************************************/ 131 132 void 133 AcpiDbSetMethodCallBreakpoint ( 134 ACPI_PARSE_OBJECT *Op) 135 { 136 137 138 if (!Op) 139 { 140 AcpiOsPrintf ("There is no method currently executing\n"); 141 return; 142 } 143 144 AcpiGbl_StepToNextCall = TRUE; 145 } 146 147 148 /******************************************************************************* 149 * 150 * FUNCTION: AcpiDbSetMethodData 151 * 152 * PARAMETERS: TypeArg - L for local, A for argument 153 * IndexArg - which one 154 * ValueArg - Value to set. 155 * 156 * RETURN: None 157 * 158 * DESCRIPTION: Set a local or argument for the running control method. 159 * NOTE: only object supported is Number. 160 * 161 ******************************************************************************/ 162 163 void 164 AcpiDbSetMethodData ( 165 char *TypeArg, 166 char *IndexArg, 167 char *ValueArg) 168 { 169 char Type; 170 UINT32 Index; 171 UINT32 Value; 172 ACPI_WALK_STATE *WalkState; 173 ACPI_OPERAND_OBJECT *ObjDesc; 174 ACPI_STATUS Status; 175 ACPI_NAMESPACE_NODE *Node; 176 177 178 /* Validate TypeArg */ 179 180 AcpiUtStrupr (TypeArg); 181 Type = TypeArg[0]; 182 if ((Type != 'L') && 183 (Type != 'A') && 184 (Type != 'N')) 185 { 186 AcpiOsPrintf ("Invalid SET operand: %s\n", TypeArg); 187 return; 188 } 189 190 Value = strtoul (ValueArg, NULL, 16); 191 192 if (Type == 'N') 193 { 194 Node = AcpiDbConvertToNode (IndexArg); 195 if (!Node) 196 { 197 return; 198 } 199 200 if (Node->Type != ACPI_TYPE_INTEGER) 201 { 202 AcpiOsPrintf ("Can only set Integer nodes\n"); 203 return; 204 } 205 ObjDesc = Node->Object; 206 ObjDesc->Integer.Value = Value; 207 return; 208 } 209 210 /* Get the index and value */ 211 212 Index = strtoul (IndexArg, NULL, 16); 213 214 WalkState = AcpiDsGetCurrentWalkState (AcpiGbl_CurrentWalkList); 215 if (!WalkState) 216 { 217 AcpiOsPrintf ("There is no method currently executing\n"); 218 return; 219 } 220 221 /* Create and initialize the new object */ 222 223 ObjDesc = AcpiUtCreateIntegerObject ((UINT64) Value); 224 if (!ObjDesc) 225 { 226 AcpiOsPrintf ("Could not create an internal object\n"); 227 return; 228 } 229 230 /* Store the new object into the target */ 231 232 switch (Type) 233 { 234 case 'A': 235 236 /* Set a method argument */ 237 238 if (Index > ACPI_METHOD_MAX_ARG) 239 { 240 AcpiOsPrintf ("Arg%u - Invalid argument name\n", 241 Index); 242 goto Cleanup; 243 } 244 245 Status = AcpiDsStoreObjectToLocal (ACPI_REFCLASS_ARG, 246 Index, ObjDesc, WalkState); 247 if (ACPI_FAILURE (Status)) 248 { 249 goto Cleanup; 250 } 251 252 ObjDesc = WalkState->Arguments[Index].Object; 253 254 AcpiOsPrintf ("Arg%u: ", Index); 255 AcpiDbDisplayInternalObject (ObjDesc, WalkState); 256 break; 257 258 case 'L': 259 260 /* Set a method local */ 261 262 if (Index > ACPI_METHOD_MAX_LOCAL) 263 { 264 AcpiOsPrintf ("Local%u - Invalid local variable name\n", 265 Index); 266 goto Cleanup; 267 } 268 269 Status = AcpiDsStoreObjectToLocal (ACPI_REFCLASS_LOCAL, 270 Index, ObjDesc, WalkState); 271 if (ACPI_FAILURE (Status)) 272 { 273 goto Cleanup; 274 } 275 276 ObjDesc = WalkState->LocalVariables[Index].Object; 277 278 AcpiOsPrintf ("Local%u: ", Index); 279 AcpiDbDisplayInternalObject (ObjDesc, WalkState); 280 break; 281 282 default: 283 284 break; 285 } 286 287 Cleanup: 288 AcpiUtRemoveReference (ObjDesc); 289 } 290 291 292 #ifdef ACPI_DISASSEMBLER 293 /******************************************************************************* 294 * 295 * FUNCTION: AcpiDbDisassembleAml 296 * 297 * PARAMETERS: Statements - Number of statements to disassemble 298 * Op - Current Op (from parse walk) 299 * 300 * RETURN: None 301 * 302 * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number 303 * of statements specified. 304 * 305 ******************************************************************************/ 306 307 void 308 AcpiDbDisassembleAml ( 309 char *Statements, 310 ACPI_PARSE_OBJECT *Op) 311 { 312 UINT32 NumStatements = 8; 313 314 315 if (!Op) 316 { 317 AcpiOsPrintf ("There is no method currently executing\n"); 318 return; 319 } 320 321 if (Statements) 322 { 323 NumStatements = strtoul (Statements, NULL, 0); 324 } 325 326 AcpiDmDisassemble (NULL, Op, NumStatements); 327 } 328 329 330 /******************************************************************************* 331 * 332 * FUNCTION: AcpiDbDisassembleMethod 333 * 334 * PARAMETERS: Name - Name of control method 335 * 336 * RETURN: None 337 * 338 * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number 339 * of statements specified. 340 * 341 ******************************************************************************/ 342 343 ACPI_STATUS 344 AcpiDbDisassembleMethod ( 345 char *Name) 346 { 347 ACPI_STATUS Status; 348 ACPI_PARSE_OBJECT *Op; 349 ACPI_WALK_STATE *WalkState; 350 ACPI_OPERAND_OBJECT *ObjDesc; 351 ACPI_NAMESPACE_NODE *Method; 352 353 354 Method = AcpiDbConvertToNode (Name); 355 if (!Method) 356 { 357 return (AE_BAD_PARAMETER); 358 } 359 360 if (Method->Type != ACPI_TYPE_METHOD) 361 { 362 ACPI_ERROR ((AE_INFO, "%s (%s): Object must be a control method", 363 Name, AcpiUtGetTypeName (Method->Type))); 364 return (AE_BAD_PARAMETER); 365 } 366 367 ObjDesc = Method->Object; 368 369 Op = AcpiPsCreateScopeOp (ObjDesc->Method.AmlStart); 370 if (!Op) 371 { 372 return (AE_NO_MEMORY); 373 } 374 375 /* Create and initialize a new walk state */ 376 377 WalkState = AcpiDsCreateWalkState (0, Op, NULL, NULL); 378 if (!WalkState) 379 { 380 return (AE_NO_MEMORY); 381 } 382 383 Status = AcpiDsInitAmlWalk (WalkState, Op, NULL, 384 ObjDesc->Method.AmlStart, 385 ObjDesc->Method.AmlLength, NULL, ACPI_IMODE_LOAD_PASS1); 386 if (ACPI_FAILURE (Status)) 387 { 388 return (Status); 389 } 390 391 Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId); 392 if (ACPI_FAILURE(Status)) 393 { 394 return (Status); 395 } 396 397 WalkState->OwnerId = ObjDesc->Method.OwnerId; 398 399 /* Push start scope on scope stack and make it current */ 400 401 Status = AcpiDsScopeStackPush (Method, 402 Method->Type, WalkState); 403 if (ACPI_FAILURE (Status)) 404 { 405 return (Status); 406 } 407 408 /* Parse the entire method AML including deferred operators */ 409 410 WalkState->ParseFlags &= ~ACPI_PARSE_DELETE_TREE; 411 WalkState->ParseFlags |= ACPI_PARSE_DISASSEMBLE; 412 413 Status = AcpiPsParseAml (WalkState); 414 if (ACPI_FAILURE(Status)) 415 { 416 return (Status); 417 } 418 419 (void) AcpiDmParseDeferredOps (Op); 420 421 /* Now we can disassemble the method */ 422 423 AcpiGbl_DmOpt_Verbose = FALSE; 424 AcpiDmDisassemble (NULL, Op, 0); 425 AcpiGbl_DmOpt_Verbose = TRUE; 426 427 AcpiPsDeleteParseTree (Op); 428 429 /* Method cleanup */ 430 431 AcpiNsDeleteNamespaceSubtree (Method); 432 AcpiNsDeleteNamespaceByOwner (ObjDesc->Method.OwnerId); 433 AcpiUtReleaseOwnerId (&ObjDesc->Method.OwnerId); 434 return (AE_OK); 435 } 436 #endif 437 438 439 /******************************************************************************* 440 * 441 * FUNCTION: AcpiDbEvaluateObject 442 * 443 * PARAMETERS: Node - Namespace node for the object 444 * 445 * RETURN: Status 446 * 447 * DESCRIPTION: Main execution function for the Evaluate/Execute/All debugger 448 * commands. 449 * 450 ******************************************************************************/ 451 452 static ACPI_STATUS 453 AcpiDbEvaluateObject ( 454 ACPI_NAMESPACE_NODE *Node) 455 { 456 char *Pathname; 457 UINT32 i; 458 ACPI_DEVICE_INFO *ObjInfo; 459 ACPI_OBJECT_LIST ParamObjects; 460 ACPI_OBJECT Params[ACPI_METHOD_NUM_ARGS]; 461 ACPI_BUFFER ReturnObj; 462 ACPI_STATUS Status; 463 464 465 Pathname = AcpiNsGetExternalPathname (Node); 466 if (!Pathname) 467 { 468 return (AE_OK); 469 } 470 471 /* Get the object info for number of method parameters */ 472 473 Status = AcpiGetObjectInfo (Node, &ObjInfo); 474 if (ACPI_FAILURE (Status)) 475 { 476 ACPI_FREE (Pathname); 477 return (Status); 478 } 479 480 ParamObjects.Pointer = NULL; 481 ParamObjects.Count = 0; 482 483 if (ObjInfo->Type == ACPI_TYPE_METHOD) 484 { 485 /* Setup default parameters */ 486 487 for (i = 0; i < ObjInfo->ParamCount; i++) 488 { 489 Params[i].Type = ACPI_TYPE_INTEGER; 490 Params[i].Integer.Value = 1; 491 } 492 493 ParamObjects.Pointer = Params; 494 ParamObjects.Count = ObjInfo->ParamCount; 495 } 496 497 ACPI_FREE (ObjInfo); 498 ReturnObj.Pointer = NULL; 499 ReturnObj.Length = ACPI_ALLOCATE_BUFFER; 500 501 /* Do the actual method execution */ 502 503 AcpiGbl_MethodExecuting = TRUE; 504 505 Status = AcpiEvaluateObject (Node, NULL, &ParamObjects, &ReturnObj); 506 AcpiGbl_MethodExecuting = FALSE; 507 508 AcpiOsPrintf ("%-32s returned %s\n", Pathname, AcpiFormatException (Status)); 509 if (ReturnObj.Length) 510 { 511 AcpiOsPrintf ("Evaluation of %s returned object %p, " 512 "external buffer length %X\n", 513 Pathname, ReturnObj.Pointer, (UINT32) ReturnObj.Length); 514 515 AcpiDbDumpExternalObject (ReturnObj.Pointer, 1); 516 AcpiOsPrintf ("\n"); 517 } 518 519 ACPI_FREE (Pathname); 520 521 /* Ignore status from method execution */ 522 523 return (AE_OK); 524 525 /* Update count, check if we have executed enough methods */ 526 527 } 528 529 /******************************************************************************* 530 * 531 * FUNCTION: AcpiDbWalkForExecute 532 * 533 * PARAMETERS: Callback from WalkNamespace 534 * 535 * RETURN: Status 536 * 537 * DESCRIPTION: Batch execution function. Evaluates all "predefined" objects -- 538 * the nameseg begins with an underscore. 539 * 540 ******************************************************************************/ 541 542 static ACPI_STATUS 543 AcpiDbWalkForExecute ( 544 ACPI_HANDLE ObjHandle, 545 UINT32 NestingLevel, 546 void *Context, 547 void **ReturnValue) 548 { 549 ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle; 550 ACPI_DB_EXECUTE_WALK *Info = (ACPI_DB_EXECUTE_WALK *) Context; 551 ACPI_STATUS Status; 552 const ACPI_PREDEFINED_INFO *Predefined; 553 554 555 Predefined = AcpiUtMatchPredefinedMethod (Node->Name.Ascii); 556 if (!Predefined) 557 { 558 return (AE_OK); 559 } 560 561 if (Node->Type == ACPI_TYPE_LOCAL_SCOPE) 562 { 563 return (AE_OK); 564 } 565 566 AcpiDbEvaluateObject (Node); 567 568 /* Ignore status from object evaluation */ 569 570 Status = AE_OK; 571 572 /* Update count, check if we have executed enough methods */ 573 574 Info->Count++; 575 if (Info->Count >= Info->MaxCount) 576 { 577 Status = AE_CTRL_TERMINATE; 578 } 579 580 return (Status); 581 } 582 583 584 /******************************************************************************* 585 * 586 * FUNCTION: AcpiDbWalkForExecuteAll 587 * 588 * PARAMETERS: Callback from WalkNamespace 589 * 590 * RETURN: Status 591 * 592 * DESCRIPTION: Batch execution function. Evaluates all objects whose path ends 593 * with the nameseg "Info->NameSeg". Used for the "ALL" command. 594 * 595 ******************************************************************************/ 596 597 static ACPI_STATUS 598 AcpiDbWalkForExecuteAll ( 599 ACPI_HANDLE ObjHandle, 600 UINT32 NestingLevel, 601 void *Context, 602 void **ReturnValue) 603 { 604 ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle; 605 ACPI_DB_EXECUTE_WALK *Info = (ACPI_DB_EXECUTE_WALK *) Context; 606 ACPI_STATUS Status; 607 608 609 if (!ACPI_COMPARE_NAMESEG (Node->Name.Ascii, Info->NameSeg)) 610 { 611 return (AE_OK); 612 } 613 614 if (Node->Type == ACPI_TYPE_LOCAL_SCOPE) 615 { 616 return (AE_OK); 617 } 618 619 /* Now evaluate the input object (node) */ 620 621 AcpiDbEvaluateObject (Node); 622 623 /* Ignore status from method execution */ 624 625 Status = AE_OK; 626 627 /* Update count of executed methods/objects */ 628 629 Info->Count++; 630 return (Status); 631 } 632 633 634 /******************************************************************************* 635 * 636 * FUNCTION: AcpiDbEvaluatePredefinedNames 637 * 638 * PARAMETERS: None 639 * 640 * RETURN: None 641 * 642 * DESCRIPTION: Namespace batch execution. Execute predefined names in the 643 * namespace, up to the max count, if specified. 644 * 645 ******************************************************************************/ 646 647 void 648 AcpiDbEvaluatePredefinedNames ( 649 void) 650 { 651 ACPI_DB_EXECUTE_WALK Info; 652 653 654 Info.Count = 0; 655 Info.MaxCount = ACPI_UINT32_MAX; 656 657 /* Search all nodes in namespace */ 658 659 (void) AcpiWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, 660 AcpiDbWalkForExecute, NULL, (void *) &Info, NULL); 661 662 AcpiOsPrintf ("Evaluated %u predefined names in the namespace\n", Info.Count); 663 } 664 665 666 /******************************************************************************* 667 * 668 * FUNCTION: AcpiDbEvaluateAll 669 * 670 * PARAMETERS: NoneAcpiGbl_DbMethodInfo 671 * 672 * RETURN: None 673 * 674 * DESCRIPTION: Namespace batch execution. Implements the "ALL" command. 675 * Execute all namepaths whose final nameseg matches the 676 * input nameseg. 677 * 678 ******************************************************************************/ 679 680 void 681 AcpiDbEvaluateAll ( 682 char *NameSeg) 683 { 684 ACPI_DB_EXECUTE_WALK Info; 685 686 687 Info.Count = 0; 688 Info.MaxCount = ACPI_UINT32_MAX; 689 ACPI_COPY_NAMESEG (Info.NameSeg, NameSeg); 690 Info.NameSeg[ACPI_NAMESEG_SIZE] = 0; 691 692 /* Search all nodes in namespace */ 693 694 (void) AcpiWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, 695 AcpiDbWalkForExecuteAll, NULL, (void *) &Info, NULL); 696 697 AcpiOsPrintf ("Evaluated %u names in the namespace\n", Info.Count); 698 } 699