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