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