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