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 #ifdef ACPI_DISASSEMBLER 49 #include <contrib/dev/acpica/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 #ifndef _KERNEL 435 AcpiGbl_DbOpt_Verbose = TRUE; 436 #endif 437 AcpiGbl_DbOpt_NoIniMethods = FALSE; 438 439 AcpiGbl_DbBuffer = AcpiOsAllocate (ACPI_DEBUG_BUFFER_SIZE); 440 if (!AcpiGbl_DbBuffer) 441 { 442 return_ACPI_STATUS (AE_NO_MEMORY); 443 } 444 memset (AcpiGbl_DbBuffer, 0, ACPI_DEBUG_BUFFER_SIZE); 445 446 /* Initial scope is the root */ 447 448 AcpiGbl_DbScopeBuf [0] = AML_ROOT_PREFIX; 449 AcpiGbl_DbScopeBuf [1] = 0; 450 AcpiGbl_DbScopeNode = AcpiGbl_RootNode; 451 452 /* 453 * If configured for multi-thread support, the debug executor runs in 454 * a separate thread so that the front end can be in another address 455 * space, environment, or even another machine. 456 */ 457 if (AcpiGbl_DebuggerConfiguration & DEBUGGER_MULTI_THREADED) 458 { 459 /* These were created with one unit, grab it */ 460 461 Status = AcpiUtAcquireMutex (ACPI_MTX_DEBUG_CMD_COMPLETE); 462 if (ACPI_FAILURE (Status)) 463 { 464 AcpiOsPrintf ("Could not get debugger mutex\n"); 465 return_ACPI_STATUS (Status); 466 } 467 468 Status = AcpiUtAcquireMutex (ACPI_MTX_DEBUG_CMD_READY); 469 if (ACPI_FAILURE (Status)) 470 { 471 AcpiOsPrintf ("Could not get debugger mutex\n"); 472 return_ACPI_STATUS (Status); 473 } 474 475 /* Create the debug execution thread to execute commands */ 476 477 Status = AcpiOsExecute (OSL_DEBUGGER_THREAD, AcpiDbExecuteThread, NULL); 478 if (ACPI_FAILURE (Status)) 479 { 480 ACPI_EXCEPTION ((AE_INFO, Status, "Could not start debugger thread")); 481 return_ACPI_STATUS (Status); 482 } 483 } 484 485 #ifndef _KERNEL 486 if (!AcpiGbl_DbOpt_Verbose) 487 { 488 AcpiGbl_DbOpt_Disasm = TRUE; 489 } 490 #endif 491 492 return_ACPI_STATUS (AE_OK); 493 } 494 495 496 /******************************************************************************* 497 * 498 * FUNCTION: AcpiDbTerminate 499 * 500 * PARAMETERS: None 501 * 502 * RETURN: None 503 * 504 * DESCRIPTION: Stop debugger 505 * 506 ******************************************************************************/ 507 508 void 509 AcpiDbTerminate ( 510 void) 511 { 512 513 if (AcpiGbl_DbBuffer) 514 { 515 AcpiOsFree (AcpiGbl_DbBuffer); 516 AcpiGbl_DbBuffer = NULL; 517 } 518 519 /* Ensure that debug output is now disabled */ 520 521 AcpiGbl_DbOutputFlags = ACPI_DB_DISABLE_OUTPUT; 522 } 523 524 525 #ifdef ACPI_OBSOLETE_FUNCTIONS 526 /******************************************************************************* 527 * 528 * FUNCTION: AcpiDbMethodEnd 529 * 530 * PARAMETERS: WalkState - Current walk 531 * 532 * RETURN: Status 533 * 534 * DESCRIPTION: Called at method termination 535 * 536 ******************************************************************************/ 537 538 void 539 AcpiDbMethodEnd ( 540 ACPI_WALK_STATE *WalkState) 541 { 542 543 if (!AcpiGbl_CmSingleStep) 544 { 545 return; 546 } 547 548 AcpiOsPrintf ("<Method Terminating>\n"); 549 550 AcpiDbStartCommand (WalkState, NULL); 551 } 552 #endif 553 554 #endif /* ACPI_DEBUGGER */ 555