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