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