1 /******************************************************************************* 2 * 3 * Module Name: dbxface - AML Debugger external interfaces 4 * 5 ******************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2016, 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 "acpi.h" 45 #include "accommon.h" 46 #include "amlcode.h" 47 #include "acdebug.h" 48 49 #ifdef ACPI_DEBUGGER 50 51 #define _COMPONENT ACPI_CA_DEBUGGER 52 ACPI_MODULE_NAME ("dbxface") 53 54 55 /* Local prototypes */ 56 57 static ACPI_STATUS 58 AcpiDbStartCommand ( 59 ACPI_WALK_STATE *WalkState, 60 ACPI_PARSE_OBJECT *Op); 61 62 #ifdef ACPI_OBSOLETE_FUNCTIONS 63 void 64 AcpiDbMethodEnd ( 65 ACPI_WALK_STATE *WalkState); 66 #endif 67 68 69 /******************************************************************************* 70 * 71 * FUNCTION: AcpiDbStartCommand 72 * 73 * PARAMETERS: WalkState - Current walk 74 * Op - Current executing Op, from AML interpreter 75 * 76 * RETURN: Status 77 * 78 * DESCRIPTION: Enter debugger command loop 79 * 80 ******************************************************************************/ 81 82 static ACPI_STATUS 83 AcpiDbStartCommand ( 84 ACPI_WALK_STATE *WalkState, 85 ACPI_PARSE_OBJECT *Op) 86 { 87 ACPI_STATUS Status; 88 89 90 /* TBD: [Investigate] are there namespace locking issues here? */ 91 92 /* AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); */ 93 94 /* Go into the command loop and await next user command */ 95 96 97 AcpiGbl_MethodExecuting = TRUE; 98 Status = AE_CTRL_TRUE; 99 while (Status == AE_CTRL_TRUE) 100 { 101 if (AcpiGbl_DebuggerConfiguration == DEBUGGER_MULTI_THREADED) 102 { 103 /* Handshake with the front-end that gets user command lines */ 104 105 AcpiOsReleaseMutex (AcpiGbl_DbCommandComplete); 106 107 Status = AcpiOsAcquireMutex (AcpiGbl_DbCommandReady, 108 ACPI_WAIT_FOREVER); 109 if (ACPI_FAILURE (Status)) 110 { 111 return (Status); 112 } 113 } 114 else 115 { 116 /* Single threaded, we must get a command line ourselves */ 117 118 /* Force output to console until a command is entered */ 119 120 AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT); 121 122 /* Different prompt if method is executing */ 123 124 if (!AcpiGbl_MethodExecuting) 125 { 126 AcpiOsPrintf ("%1c ", ACPI_DEBUGGER_COMMAND_PROMPT); 127 } 128 else 129 { 130 AcpiOsPrintf ("%1c ", ACPI_DEBUGGER_EXECUTE_PROMPT); 131 } 132 133 /* Get the user input line */ 134 135 Status = AcpiOsGetLine (AcpiGbl_DbLineBuf, 136 ACPI_DB_LINE_BUFFER_SIZE, NULL); 137 if (ACPI_FAILURE (Status)) 138 { 139 ACPI_EXCEPTION ((AE_INFO, Status, 140 "While parsing command line")); 141 return (Status); 142 } 143 } 144 145 Status = AcpiDbCommandDispatch (AcpiGbl_DbLineBuf, WalkState, Op); 146 } 147 148 /* AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); */ 149 150 return (Status); 151 } 152 153 154 /******************************************************************************* 155 * 156 * FUNCTION: AcpiDbSignalBreakPoint 157 * 158 * PARAMETERS: WalkState - Current walk 159 * 160 * RETURN: Status 161 * 162 * DESCRIPTION: Called for AML_BREAK_POINT_OP 163 * 164 ******************************************************************************/ 165 166 void 167 AcpiDbSignalBreakPoint ( 168 ACPI_WALK_STATE *WalkState) 169 { 170 171 #ifndef ACPI_APPLICATION 172 if (AcpiGbl_DbThreadId != AcpiOsGetThreadId ()) 173 { 174 return; 175 } 176 #endif 177 178 /* 179 * Set the single-step flag. This will cause the debugger (if present) 180 * to break to the console within the AML debugger at the start of the 181 * next AML instruction. 182 */ 183 AcpiGbl_CmSingleStep = TRUE; 184 AcpiOsPrintf ("**break** Executed AML BreakPoint opcode\n"); 185 } 186 187 188 /******************************************************************************* 189 * 190 * FUNCTION: AcpiDbSingleStep 191 * 192 * PARAMETERS: WalkState - Current walk 193 * Op - Current executing op (from aml interpreter) 194 * OpcodeClass - Class of the current AML Opcode 195 * 196 * RETURN: Status 197 * 198 * DESCRIPTION: Called just before execution of an AML opcode. 199 * 200 ******************************************************************************/ 201 202 ACPI_STATUS 203 AcpiDbSingleStep ( 204 ACPI_WALK_STATE *WalkState, 205 ACPI_PARSE_OBJECT *Op, 206 UINT32 OpcodeClass) 207 { 208 ACPI_PARSE_OBJECT *Next; 209 ACPI_STATUS Status = AE_OK; 210 UINT32 OriginalDebugLevel; 211 ACPI_PARSE_OBJECT *DisplayOp; 212 ACPI_PARSE_OBJECT *ParentOp; 213 UINT32 AmlOffset; 214 215 216 ACPI_FUNCTION_ENTRY (); 217 218 219 #ifndef ACPI_APPLICATION 220 if (AcpiGbl_DbThreadId != AcpiOsGetThreadId ()) 221 { 222 return (AE_OK); 223 } 224 #endif 225 226 /* Check the abort flag */ 227 228 if (AcpiGbl_AbortMethod) 229 { 230 AcpiGbl_AbortMethod = FALSE; 231 return (AE_ABORT_METHOD); 232 } 233 234 AmlOffset = (UINT32) ACPI_PTR_DIFF (Op->Common.Aml, 235 WalkState->ParserState.AmlStart); 236 237 /* Check for single-step breakpoint */ 238 239 if (WalkState->MethodBreakpoint && 240 (WalkState->MethodBreakpoint <= AmlOffset)) 241 { 242 /* Check if the breakpoint has been reached or passed */ 243 /* Hit the breakpoint, resume single step, reset breakpoint */ 244 245 AcpiOsPrintf ("***Break*** at AML offset %X\n", AmlOffset); 246 AcpiGbl_CmSingleStep = TRUE; 247 AcpiGbl_StepToNextCall = FALSE; 248 WalkState->MethodBreakpoint = 0; 249 } 250 251 /* Check for user breakpoint (Must be on exact Aml offset) */ 252 253 else if (WalkState->UserBreakpoint && 254 (WalkState->UserBreakpoint == AmlOffset)) 255 { 256 AcpiOsPrintf ("***UserBreakpoint*** at AML offset %X\n", 257 AmlOffset); 258 AcpiGbl_CmSingleStep = TRUE; 259 AcpiGbl_StepToNextCall = FALSE; 260 WalkState->MethodBreakpoint = 0; 261 } 262 263 /* 264 * Check if this is an opcode that we are interested in -- 265 * namely, opcodes that have arguments 266 */ 267 if (Op->Common.AmlOpcode == AML_INT_NAMEDFIELD_OP) 268 { 269 return (AE_OK); 270 } 271 272 switch (OpcodeClass) 273 { 274 case AML_CLASS_UNKNOWN: 275 case AML_CLASS_ARGUMENT: /* constants, literals, etc. do nothing */ 276 277 return (AE_OK); 278 279 default: 280 281 /* All other opcodes -- continue */ 282 break; 283 } 284 285 /* 286 * Under certain debug conditions, display this opcode and its operands 287 */ 288 if ((AcpiGbl_DbOutputToFile) || 289 (AcpiGbl_CmSingleStep) || 290 (AcpiDbgLevel & ACPI_LV_PARSE)) 291 { 292 if ((AcpiGbl_DbOutputToFile) || 293 (AcpiDbgLevel & ACPI_LV_PARSE)) 294 { 295 AcpiOsPrintf ("\n[AmlDebug] Next AML Opcode to execute:\n"); 296 } 297 298 /* 299 * Display this op (and only this op - zero out the NEXT field 300 * temporarily, and disable parser trace output for the duration of 301 * the display because we don't want the extraneous debug output) 302 */ 303 OriginalDebugLevel = AcpiDbgLevel; 304 AcpiDbgLevel &= ~(ACPI_LV_PARSE | ACPI_LV_FUNCTIONS); 305 Next = Op->Common.Next; 306 Op->Common.Next = NULL; 307 308 309 DisplayOp = Op; 310 ParentOp = Op->Common.Parent; 311 if (ParentOp) 312 { 313 if ((WalkState->ControlState) && 314 (WalkState->ControlState->Common.State == 315 ACPI_CONTROL_PREDICATE_EXECUTING)) 316 { 317 /* 318 * We are executing the predicate of an IF or WHILE statement 319 * Search upwards for the containing IF or WHILE so that the 320 * entire predicate can be displayed. 321 */ 322 while (ParentOp) 323 { 324 if ((ParentOp->Common.AmlOpcode == AML_IF_OP) || 325 (ParentOp->Common.AmlOpcode == AML_WHILE_OP)) 326 { 327 DisplayOp = ParentOp; 328 break; 329 } 330 ParentOp = ParentOp->Common.Parent; 331 } 332 } 333 else 334 { 335 while (ParentOp) 336 { 337 if ((ParentOp->Common.AmlOpcode == AML_IF_OP) || 338 (ParentOp->Common.AmlOpcode == AML_ELSE_OP) || 339 (ParentOp->Common.AmlOpcode == AML_SCOPE_OP) || 340 (ParentOp->Common.AmlOpcode == AML_METHOD_OP) || 341 (ParentOp->Common.AmlOpcode == AML_WHILE_OP)) 342 { 343 break; 344 } 345 DisplayOp = ParentOp; 346 ParentOp = ParentOp->Common.Parent; 347 } 348 } 349 } 350 351 /* Now we can display it */ 352 353 #ifdef ACPI_DISASSEMBLER 354 AcpiDmDisassemble (WalkState, DisplayOp, ACPI_UINT32_MAX); 355 #endif 356 357 if ((Op->Common.AmlOpcode == AML_IF_OP) || 358 (Op->Common.AmlOpcode == AML_WHILE_OP)) 359 { 360 if (WalkState->ControlState->Common.Value) 361 { 362 AcpiOsPrintf ("Predicate = [True], IF block was executed\n"); 363 } 364 else 365 { 366 AcpiOsPrintf ("Predicate = [False], Skipping IF block\n"); 367 } 368 } 369 else if (Op->Common.AmlOpcode == AML_ELSE_OP) 370 { 371 AcpiOsPrintf ("Predicate = [False], ELSE block was executed\n"); 372 } 373 374 /* Restore everything */ 375 376 Op->Common.Next = Next; 377 AcpiOsPrintf ("\n"); 378 if ((AcpiGbl_DbOutputToFile) || 379 (AcpiDbgLevel & ACPI_LV_PARSE)) 380 { 381 AcpiOsPrintf ("\n"); 382 } 383 AcpiDbgLevel = OriginalDebugLevel; 384 } 385 386 /* If we are not single stepping, just continue executing the method */ 387 388 if (!AcpiGbl_CmSingleStep) 389 { 390 return (AE_OK); 391 } 392 393 /* 394 * If we are executing a step-to-call command, 395 * Check if this is a method call. 396 */ 397 if (AcpiGbl_StepToNextCall) 398 { 399 if (Op->Common.AmlOpcode != AML_INT_METHODCALL_OP) 400 { 401 /* Not a method call, just keep executing */ 402 403 return (AE_OK); 404 } 405 406 /* Found a method call, stop executing */ 407 408 AcpiGbl_StepToNextCall = FALSE; 409 } 410 411 /* 412 * If the next opcode is a method call, we will "step over" it 413 * by default. 414 */ 415 if (Op->Common.AmlOpcode == AML_INT_METHODCALL_OP) 416 { 417 /* Force no more single stepping while executing called method */ 418 419 AcpiGbl_CmSingleStep = FALSE; 420 421 /* 422 * Set the breakpoint on/before the call, it will stop execution 423 * as soon as we return 424 */ 425 WalkState->MethodBreakpoint = 1; /* Must be non-zero! */ 426 } 427 428 429 Status = AcpiDbStartCommand (WalkState, Op); 430 431 /* User commands complete, continue execution of the interrupted method */ 432 433 return (Status); 434 } 435 436 437 /******************************************************************************* 438 * 439 * FUNCTION: AcpiInitializeDebugger 440 * 441 * PARAMETERS: None 442 * 443 * RETURN: Status 444 * 445 * DESCRIPTION: Init and start debugger 446 * 447 ******************************************************************************/ 448 449 ACPI_STATUS 450 AcpiInitializeDebugger ( 451 void) 452 { 453 ACPI_STATUS Status; 454 455 456 ACPI_FUNCTION_TRACE (AcpiInitializeDebugger); 457 458 459 /* Init globals */ 460 461 AcpiGbl_DbBuffer = NULL; 462 AcpiGbl_DbFilename = NULL; 463 AcpiGbl_DbOutputToFile = FALSE; 464 465 AcpiGbl_DbDebugLevel = ACPI_LV_VERBOSITY2; 466 AcpiGbl_DbConsoleDebugLevel = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES; 467 AcpiGbl_DbOutputFlags = ACPI_DB_CONSOLE_OUTPUT; 468 469 AcpiGbl_DbOpt_NoIniMethods = FALSE; 470 471 AcpiGbl_DbBuffer = AcpiOsAllocate (ACPI_DEBUG_BUFFER_SIZE); 472 if (!AcpiGbl_DbBuffer) 473 { 474 return_ACPI_STATUS (AE_NO_MEMORY); 475 } 476 memset (AcpiGbl_DbBuffer, 0, ACPI_DEBUG_BUFFER_SIZE); 477 478 /* Initial scope is the root */ 479 480 AcpiGbl_DbScopeBuf [0] = AML_ROOT_PREFIX; 481 AcpiGbl_DbScopeBuf [1] = 0; 482 AcpiGbl_DbScopeNode = AcpiGbl_RootNode; 483 484 /* Initialize user commands loop */ 485 486 AcpiGbl_DbTerminateLoop = FALSE; 487 488 /* 489 * If configured for multi-thread support, the debug executor runs in 490 * a separate thread so that the front end can be in another address 491 * space, environment, or even another machine. 492 */ 493 if (AcpiGbl_DebuggerConfiguration & DEBUGGER_MULTI_THREADED) 494 { 495 /* These were created with one unit, grab it */ 496 497 Status = AcpiOsAcquireMutex (AcpiGbl_DbCommandComplete, 498 ACPI_WAIT_FOREVER); 499 if (ACPI_FAILURE (Status)) 500 { 501 AcpiOsPrintf ("Could not get debugger mutex\n"); 502 return_ACPI_STATUS (Status); 503 } 504 505 Status = AcpiOsAcquireMutex (AcpiGbl_DbCommandReady, 506 ACPI_WAIT_FOREVER); 507 if (ACPI_FAILURE (Status)) 508 { 509 AcpiOsPrintf ("Could not get debugger mutex\n"); 510 return_ACPI_STATUS (Status); 511 } 512 513 /* Create the debug execution thread to execute commands */ 514 515 AcpiGbl_DbThreadsTerminated = FALSE; 516 Status = AcpiOsExecute (OSL_DEBUGGER_MAIN_THREAD, 517 AcpiDbExecuteThread, NULL); 518 if (ACPI_FAILURE (Status)) 519 { 520 ACPI_EXCEPTION ((AE_INFO, Status, 521 "Could not start debugger thread")); 522 AcpiGbl_DbThreadsTerminated = TRUE; 523 return_ACPI_STATUS (Status); 524 } 525 } 526 else 527 { 528 AcpiGbl_DbThreadId = AcpiOsGetThreadId (); 529 } 530 531 return_ACPI_STATUS (AE_OK); 532 } 533 534 ACPI_EXPORT_SYMBOL (AcpiInitializeDebugger) 535 536 537 /******************************************************************************* 538 * 539 * FUNCTION: AcpiTerminateDebugger 540 * 541 * PARAMETERS: None 542 * 543 * RETURN: None 544 * 545 * DESCRIPTION: Stop debugger 546 * 547 ******************************************************************************/ 548 549 void 550 AcpiTerminateDebugger ( 551 void) 552 { 553 554 /* Terminate the AML Debugger */ 555 556 AcpiGbl_DbTerminateLoop = TRUE; 557 558 if (AcpiGbl_DebuggerConfiguration & DEBUGGER_MULTI_THREADED) 559 { 560 AcpiOsReleaseMutex (AcpiGbl_DbCommandReady); 561 562 /* Wait the AML Debugger threads */ 563 564 while (!AcpiGbl_DbThreadsTerminated) 565 { 566 AcpiOsSleep (100); 567 } 568 } 569 570 if (AcpiGbl_DbBuffer) 571 { 572 AcpiOsFree (AcpiGbl_DbBuffer); 573 AcpiGbl_DbBuffer = NULL; 574 } 575 576 /* Ensure that debug output is now disabled */ 577 578 AcpiGbl_DbOutputFlags = ACPI_DB_DISABLE_OUTPUT; 579 } 580 581 ACPI_EXPORT_SYMBOL (AcpiTerminateDebugger) 582 583 584 /******************************************************************************* 585 * 586 * FUNCTION: AcpiSetDebuggerThreadId 587 * 588 * PARAMETERS: ThreadId - Debugger thread ID 589 * 590 * RETURN: None 591 * 592 * DESCRIPTION: Set debugger thread ID 593 * 594 ******************************************************************************/ 595 596 void 597 AcpiSetDebuggerThreadId ( 598 ACPI_THREAD_ID ThreadId) 599 { 600 AcpiGbl_DbThreadId = ThreadId; 601 } 602 603 ACPI_EXPORT_SYMBOL (AcpiSetDebuggerThreadId) 604 605 #endif /* ACPI_DEBUGGER */ 606