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