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