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 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_BREAK_POINT_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 ("\n[AmlDebug] 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 Status = AcpiDbStartCommand (WalkState, Op); 409 410 /* User commands complete, continue execution of the interrupted method */ 411 412 return (Status); 413 } 414 415 416 /******************************************************************************* 417 * 418 * FUNCTION: AcpiInitializeDebugger 419 * 420 * PARAMETERS: None 421 * 422 * RETURN: Status 423 * 424 * DESCRIPTION: Init and start debugger 425 * 426 ******************************************************************************/ 427 428 ACPI_STATUS 429 AcpiInitializeDebugger ( 430 void) 431 { 432 ACPI_STATUS Status; 433 434 435 ACPI_FUNCTION_TRACE (AcpiInitializeDebugger); 436 437 438 /* Init globals */ 439 440 AcpiGbl_DbBuffer = NULL; 441 AcpiGbl_DbFilename = NULL; 442 AcpiGbl_DbOutputToFile = FALSE; 443 444 AcpiGbl_DbDebugLevel = ACPI_LV_VERBOSITY2; 445 AcpiGbl_DbConsoleDebugLevel = ACPI_NORMAL_DEFAULT | ACPI_LV_TABLES; 446 AcpiGbl_DbOutputFlags = ACPI_DB_CONSOLE_OUTPUT; 447 448 AcpiGbl_DbOpt_NoIniMethods = FALSE; 449 450 AcpiGbl_DbBuffer = AcpiOsAllocate (ACPI_DEBUG_BUFFER_SIZE); 451 if (!AcpiGbl_DbBuffer) 452 { 453 return_ACPI_STATUS (AE_NO_MEMORY); 454 } 455 memset (AcpiGbl_DbBuffer, 0, ACPI_DEBUG_BUFFER_SIZE); 456 457 /* Initial scope is the root */ 458 459 AcpiGbl_DbScopeBuf [0] = AML_ROOT_PREFIX; 460 AcpiGbl_DbScopeBuf [1] = 0; 461 AcpiGbl_DbScopeNode = AcpiGbl_RootNode; 462 463 /* Initialize user commands loop */ 464 465 AcpiGbl_DbTerminateLoop = FALSE; 466 467 /* 468 * If configured for multi-thread support, the debug executor runs in 469 * a separate thread so that the front end can be in another address 470 * space, environment, or even another machine. 471 */ 472 if (AcpiGbl_DebuggerConfiguration & DEBUGGER_MULTI_THREADED) 473 { 474 /* These were created with one unit, grab it */ 475 476 Status = AcpiOsInitializeDebugger (); 477 if (ACPI_FAILURE (Status)) 478 { 479 AcpiOsPrintf ("Could not get debugger mutex\n"); 480 return_ACPI_STATUS (Status); 481 } 482 483 /* Create the debug execution thread to execute commands */ 484 485 AcpiGbl_DbThreadsTerminated = FALSE; 486 Status = AcpiOsExecute (OSL_DEBUGGER_MAIN_THREAD, 487 AcpiDbExecuteThread, NULL); 488 if (ACPI_FAILURE (Status)) 489 { 490 ACPI_EXCEPTION ((AE_INFO, Status, 491 "Could not start debugger thread")); 492 AcpiGbl_DbThreadsTerminated = TRUE; 493 return_ACPI_STATUS (Status); 494 } 495 } 496 else 497 { 498 AcpiGbl_DbThreadId = AcpiOsGetThreadId (); 499 } 500 501 return_ACPI_STATUS (AE_OK); 502 } 503 504 ACPI_EXPORT_SYMBOL (AcpiInitializeDebugger) 505 506 507 /******************************************************************************* 508 * 509 * FUNCTION: AcpiTerminateDebugger 510 * 511 * PARAMETERS: None 512 * 513 * RETURN: None 514 * 515 * DESCRIPTION: Stop debugger 516 * 517 ******************************************************************************/ 518 519 void 520 AcpiTerminateDebugger ( 521 void) 522 { 523 524 /* Terminate the AML Debugger */ 525 526 AcpiGbl_DbTerminateLoop = TRUE; 527 528 if (AcpiGbl_DebuggerConfiguration & DEBUGGER_MULTI_THREADED) 529 { 530 /* Wait the AML Debugger threads */ 531 532 while (!AcpiGbl_DbThreadsTerminated) 533 { 534 AcpiOsSleep (100); 535 } 536 537 AcpiOsTerminateDebugger (); 538 } 539 540 if (AcpiGbl_DbBuffer) 541 { 542 AcpiOsFree (AcpiGbl_DbBuffer); 543 AcpiGbl_DbBuffer = NULL; 544 } 545 546 /* Ensure that debug output is now disabled */ 547 548 AcpiGbl_DbOutputFlags = ACPI_DB_DISABLE_OUTPUT; 549 } 550 551 ACPI_EXPORT_SYMBOL (AcpiTerminateDebugger) 552 553 554 /******************************************************************************* 555 * 556 * FUNCTION: AcpiSetDebuggerThreadId 557 * 558 * PARAMETERS: ThreadId - Debugger thread ID 559 * 560 * RETURN: None 561 * 562 * DESCRIPTION: Set debugger thread ID 563 * 564 ******************************************************************************/ 565 566 void 567 AcpiSetDebuggerThreadId ( 568 ACPI_THREAD_ID ThreadId) 569 { 570 AcpiGbl_DbThreadId = ThreadId; 571 } 572 573 ACPI_EXPORT_SYMBOL (AcpiSetDebuggerThreadId) 574 575 #endif /* ACPI_DEBUGGER */ 576