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