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